我面临的一个问题是,在JavaScript
中操纵数组或对象时,我总是重复自己。我们正逐渐远离jQuery
年龄,我们可以简单地将统计数据转换为DOM
或从[
{
"data": [
{
"name": "item1",
"checked": false
},
{
"name": "item2",
"checked": false
}
]
}
]
修改。
以此嵌套数组对象为例
checked
为了更改item2
的{{1}}属性,我必须做2个循环
const newData = data.map(o=>{
return {
...o,
data: o.data.map(o2=>{
if(o2.name === 'item2'){
return{
...o2,
'checked': true
}
}
return o2
})
}
})
这个问题有更好的选择吗?
答案 0 :(得分:1)
一种方法是认识到复杂数据结构中的每个嵌套级别都是一个"仿函数" (超出了这个答案的范围来解释它,但在线有很多很好的解释)。
仿函数-101的解释是它是" mappability"概念的概括,因此您可以映射数组,对象,可观察对象,各种怪异的东西,同时保留它们的结构。
无论如何,鉴于您的数据结构是嵌入在仿函数中的仿函数中的仿函数,您可以通过简单地将map
函数与其自身组合在一起,可以映射到最深层次。嵌套仿函数结构。
E.g。在您的情况下,您可以使用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,在他的博客文章"语义编辑器组合器"。
答案 1 :(得分:0)
这取决于你如何构建你的州前。如果用这种方式表示相同的数据
{
item1 : {name:"item1" ,checked:true}
...
}
可能会导致无循环的简单操作,或者如果你有id,你也可以使用它们。
了解normalizr对构建状态link非常有帮助。
答案 2 :(得分: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
来告诉我何时检查外部数据或内部数据。并相应地改变指数。
尽管如此,我必须承认,你仍然无法解决这个事实,最终会做同样数量的迭代。