不可变 js - 以声明方式从深层嵌套对象中提取值的最佳方式?
Immutable js - best way to extract values from a deeply nested object in a declarative way?
假设我从一个 API 调用中得到一个 json 返回,这个形状一旦被解析:
const foos = {
foo1: {
bar1: [{a:1},{a:2},{a:3}],
bar2: [{a:4},{a:5},{a:6}],
bar3: [{a:7},{a:8},{a:9}]
},
foo2: {
bar4: [{a:10},{a:11},{a:12}],
bar5: [{a:13},{a:14},{a:15}]
}
}
然后,我将其包装在 fromJs()
中以使其不可变。
接下来,我需要遍历该对象以通过这种方式提取值并用它做任何我想做的事:
var obj = {aValue: 0}
Object.keys(foos).forEach( key => {
Object.keys(foos[key]).forEach( nestedKey => {
foos[key][nestedKey].forEach(el => {
obj.aValue = el.a
console.log(obj)
})
})
})
在控制台中:
{ aValue: 1 }
{ aValue: 2 }
{ aValue: 3 }
{ aValue: 4 }
{ aValue: 5 }
{ aValue: 6 }
{ aValue: 7 }
{ aValue: 8 }
{ aValue: 9 }
{ aValue: 10 }
{ aValue: 11 }
{ aValue: 12 }
{ aValue: 13 }
{ aValue: 14 }
{ aValue: 15 }
以声明方式使用 Immutable JS 执行此操作的最佳方法是什么?
您可以使用 flatten
,它会创建一个新的扁平化集合。
// flatten the first two levels
const foos = Immutable.fromJS({...});
const flatCollection = foos.flatten(2);
flatCollection.forEach(val => console.log('flat entry', val.get('a')));
如果您只想遍历数据而不是创建集合,使用 Immutable 的 forEach
遍历层可能是更好(也更快)的方法。这也可以与 .reduce
结合使用
const foos = Immutable.fromJS({
foo1: {
bar1: [{a:1},{a:2},{a:3}],
bar2: [{a:4},{a:5},{a:6}],
bar3: [{a:7},{a:8},{a:9}]
},
foo2: {
bar4: [{a:10},{a:11},{a:12}],
bar5: [{a:13},{a:14},{a:15}]
}
});
// go into all immmutable collections and process their values
function deepLoop(value, key) {
if (Immutable.isCollection(value)) {
value.forEach(deepLoop);
} else {
console.log('primitive entry', key, value);
}
}
foos.forEach(deepLoop);
// go into all maps and process the lists differently
function deepMap(value, key, context) {
if (Immutable.Map.isMap(value)) {
value.forEach(deepMap, key);
} else {
value.forEach(val => console.log('list entry', val.get('a')));
}
}
foos.forEach(deepMap);
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/4.0.0-rc.12/immutable.js"></script>
假设我从一个 API 调用中得到一个 json 返回,这个形状一旦被解析:
const foos = {
foo1: {
bar1: [{a:1},{a:2},{a:3}],
bar2: [{a:4},{a:5},{a:6}],
bar3: [{a:7},{a:8},{a:9}]
},
foo2: {
bar4: [{a:10},{a:11},{a:12}],
bar5: [{a:13},{a:14},{a:15}]
}
}
然后,我将其包装在 fromJs()
中以使其不可变。
接下来,我需要遍历该对象以通过这种方式提取值并用它做任何我想做的事:
var obj = {aValue: 0}
Object.keys(foos).forEach( key => {
Object.keys(foos[key]).forEach( nestedKey => {
foos[key][nestedKey].forEach(el => {
obj.aValue = el.a
console.log(obj)
})
})
})
在控制台中:
{ aValue: 1 }
{ aValue: 2 }
{ aValue: 3 }
{ aValue: 4 }
{ aValue: 5 }
{ aValue: 6 }
{ aValue: 7 }
{ aValue: 8 }
{ aValue: 9 }
{ aValue: 10 }
{ aValue: 11 }
{ aValue: 12 }
{ aValue: 13 }
{ aValue: 14 }
{ aValue: 15 }
以声明方式使用 Immutable JS 执行此操作的最佳方法是什么?
您可以使用 flatten
,它会创建一个新的扁平化集合。
// flatten the first two levels
const foos = Immutable.fromJS({...});
const flatCollection = foos.flatten(2);
flatCollection.forEach(val => console.log('flat entry', val.get('a')));
如果您只想遍历数据而不是创建集合,使用 Immutable 的 forEach
遍历层可能是更好(也更快)的方法。这也可以与 .reduce
const foos = Immutable.fromJS({
foo1: {
bar1: [{a:1},{a:2},{a:3}],
bar2: [{a:4},{a:5},{a:6}],
bar3: [{a:7},{a:8},{a:9}]
},
foo2: {
bar4: [{a:10},{a:11},{a:12}],
bar5: [{a:13},{a:14},{a:15}]
}
});
// go into all immmutable collections and process their values
function deepLoop(value, key) {
if (Immutable.isCollection(value)) {
value.forEach(deepLoop);
} else {
console.log('primitive entry', key, value);
}
}
foos.forEach(deepLoop);
// go into all maps and process the lists differently
function deepMap(value, key, context) {
if (Immutable.Map.isMap(value)) {
value.forEach(deepMap, key);
} else {
value.forEach(val => console.log('list entry', val.get('a')));
}
}
foos.forEach(deepMap);
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/4.0.0-rc.12/immutable.js"></script>