更新嵌套属性,没有多个循环

问题描述 投票:2回答:3

我面临的一个问题是,当我在JavaScript中操纵数组或对象时,我总是重复自己。我们正在逐渐远离jQuery时代,我们可以简单地从DOM获取和修改统计数据。

以这个嵌套的对象数组为例

[
  {
    "data": [
      {
        "name": "item1",
        "checked": false
      },
      {
        "name": "item2",
        "checked": false
      }
    ]
  }
]

为了改变checkeditem2属性,我必须做2个循环

const newData = data.map(o=>{
  return {
    ...o,
    data: o.data.map(o2=>{
     if(o2.name === 'item2'){
       return{
         ...o2,
         'checked': true
       }
     }
     return o2
   })
  }
})

对这个问题有更好的选择吗?

javascript reactjs
3个回答
1
投票

一种方法是认识到复杂数据结构中的每个嵌套级别都是一个“函子”(超出了解释它的答案的范围,但在线有很多很好的解释)。

functor-101的解释是它是“mappability”概念的概括,因此你可以映射数组,对象,observable,各种怪异的东西,同时保留它们的结构。

无论如何,鉴于您的数据结构是嵌入在仿函数中的仿函数中的仿函数,您可以通过简单地将map函数与其自身组合,与嵌套仿函数结构中的级别一样多次映射到最深层次。

例如。在你的情况下你可以使用map3来做:

const result = map3(x => x.name === "item2" ? { ...x, checked: true } : x)(data)

这是一个完整的JS实现(我实现了FP库内联而不是使用依赖来阐明正在发生的事情):

// FP utils (you can use a library like Sanctuary or Ramda to get these)
const merge = (o1, o2) => ({
  ...o1,
  ...o2
})
const compose = fns => fns.reduce((f, g) => (...args) => f(g(...args)))

const mapArr = f => a => a.map(f)
const mapObj = f => o =>
  Object.keys(o)
    .map(k => ({
      [k]: f(o[k])
    }))
    .reduce(merge)
const mapImpls = new Map([[Object, mapObj], [Array, mapArr]])

const map = f => x => mapImpls.get(x.constructor)(f)(x)

const map2 = compose([map, map])
const map3 = compose([map, map, map])
const map4 = compose([map, map, map, map])
// ...

// Your code
const data = [
  {
    data: [
      {
        name: "item1",
        checked: false
      },
      {
        name: "item2",
        checked: false
      }
    ]
  }
]
const projection = x =>
  x.name === "item2"
    ? {
        ...x,
        checked: true
      }
    : x
const result = map3(projection)(data)
console.log(result)

据我所知,第一个给这个模式命名的人是Conal Elliott,在他的博客文章“语义编辑器组合器”中。


0
投票

这取决于你如何构建你的州前。如果用这种方式表示相同的数据

{
 item1 : {name:"item1" ,checked:true} 
 ...
}

可以导致没有循环的简单操作,或者如果你有id,你也可以使用它们。 了解normalizr对于构建状态link非常有帮助。


0
投票
let your_data = [
    {
    "data": [
        {
        "name": "item1",
        "checked": false
        },
        {
        "name": "item2",
        "checked": false
        }
    ]
    }
]
let data = [...your_data];
let index = 0, mod = 0, flag = false, rew_array = [];
while(index < data.length){
    if(!flag){
        new_array[index] = {...data[index]};
        mod = data[index].data.length;
        index = 0;
        flag = true;
    }else{
        let __index = new_array.length-1;
        let array = new_array[__index].data;
        if(array[index].name === 'item2'){
            array[index] = {
                ...array[index],
                'checked': true
            }
        }
        if(index > mod) {
            index = new_array.length;
            mod = 0;
            flag = false;
        }
    }
    index++;
}

console.log(data);

既然你已经了解了数据的结构,你可以通过一个while循环运行它,其中索引总是根据一些偏移量mod而改变。在这个例子中,我正在使用flag来告诉我何时检查外部数据或内部数据。并相应地更改索引。

虽然,我必须承认,没有解决这个事实,你仍然会,最终做同样数量的迭代。

© www.soinside.com 2019 - 2024. All rights reserved.