以下函数将对象附加到嵌套数组中(通过递归搜索):
function appendDeep (arr, obj, newObj) {
if (arr.indexOf(obj) !== -1) {
arr.splice(arr.indexOf(obj) + 1, 0, newObj)
} else {
arr.map(item => {
if (item.children) spliceDeep(item.children, obj)
})
}
}
示例:
const colors = {
children: [
{
name: 'white',
},
{
name: 'yellow',
children: [
{
name: 'black'
}
]
}
]
}
const color = {
name: 'black'
}
const newColor = {
name: 'brown'
}
appendDeep(colors.children, color, newColor)
结果:
children: [
[
{
name: 'white',
},
{
name: 'yellow',
children: [
{
name: 'black'
},
{
name: 'brown'
}
]
}
]
]
正如您所看到的,appendDeep
会返回副作用;它会修改arr
。所以我决定返回数组(因此函数会变得纯净):
function findDeep (arr, obj) {
if (arr.indexOf(obj) !== -1) {
console.log(arr)
return arr
} else {
arr.map(item => {
if (item.children) findDeep(item.children, obj)
})
}
}
并使用这样的新功能:
const newArr = findDeep(colors.children, color)
newArr.splice(newArr.indexOf(color) + 1, 0, newColor)
但是我收到了这个错误:
bundle.js:19893 Uncaught TypeError: Cannot read property 'splice' of undefined
我做错了什么?
(注意:这里是CodePen。)
(注2:console.log(arr)
确实返回嵌套的子项。但由于某种原因,它们在函数之外变为undefined
。)
答案 0 :(得分:2)
您未在findDeep
内向您返回递归map
方法。返回表示递归工作,因为条件分支没有从map中返回任何内容。因此,您获得的结果为undefined
。 JSBin
答案 1 :(得分:1)
这是一项使用Array#some
的thisArgs
的提案。
function appendDeep(object, search, insert) {
function iter(a) {
if (a.name === search.name) {
this.children.push(insert);
return true;
}
return Array.isArray(a.children) && a.children.some(iter, a);
}
object.children.some(iter, object);
}
var colors = { children: [{ name: 'white', }, { name: 'yellow', children: [{ name: 'black' }] }] },
color = { name: 'black' },
newColor = { name: 'brown' };
appendDeep(colors, color, newColor);
document.write('<pre>' + JSON.stringify(colors, 0, 4) + '</pre>');
&#13;
答案 2 :(得分:1)
首先,一个find方法将返回所请求项目所在的数组(作为直接子项)。
function findDeep(arr, obj) {
return arr.map((item) => {
if (item.name === obj.name) {
return arr;
} else if (item.children) {
return findDeep(item.children, obj);
} else {
return undefined;
}
}).reduce((prev, cur) => {
return prev ? prev : cur;
});
}
您可以使用它将项目附加到列表中,但仍会修改原始数组:
function appendDeep(arr, color, newColor) {
let found = findDeep(arr, color);
if (found) {
found.splice(found.indexOf(color) + 1, 0, newColor);
}
return arr;
}
如果您不想修改原始数组,事情会变得更加复杂。这是因为标准数组函数(如push
和splice
)将修改原始数组。没有快速解决办法,至少不是我所知道的,因为最好不要再克隆任何比你真正需要的东西了。
您不需要克隆black
,但您确实需要克隆包含它的数组(它可以简单地将现有对象重用为黑色。)这意味着黄色对象也需要克隆(使用克隆的数组)和黄色所在的数组需要克隆。但是,在同一个数组中的white不会被修改,也不需要克隆。我还没弄明白如何正确地做到这一点。