检索属性'x'属性内所有对象的'y'使用递归

Retrieve property 'x' of all objects inside property 'y' with recursion

本文关键字:属性 递归 检索 对象      更新时间:2023-09-26

考虑以下示例:

<script>
var McDuffFamily = {
    name: "Jack McDuff I",
    children: [
        {
            name:"Jack McDuff II",
            children: [
                {
                    name:"Jack McDuff III",
                    children: [
                        {
                            name:"Jack McDuff IV"
                        },
                        {
                            name:"Jonh McDuff I",
                            children: [
                                {
                                    name:"Jonh McDuff I",
                                    children: []
                                }
                            ]
                        }
                    ]
                },
                {
                    name:"Shena McDuff"
                }
            ]
        },
        {
            name:"Poor bastard",
            children: [
                {
                    name:"Citzen I",
                    children: [
                        {
                            name:"Darth Vader"
                        }
                    ]
                },
                {
                    name:"Citzen II",
                    children: []
                }
            ]
        }
    ]
};
</script>

有没有什么无痛的方法可以检索所有"Jack McDuff I"后代的名字?

不使用递归:

var tree =[McDuffFamily];
var kids = [];
for (i=0; i < tree.length; i++) {
   tree[i] && tree.push.apply(tree, tree[i].childrens)
   kids.push(tree[i]);
}
kids; // all children

奇怪部分的分解:

tree[i] && tree.push.apply(tree, tree[i].childrens);

tree[i] &&用于短路评估,确保当我调用tree[i].childrentree[i]不为空

tree.push.apply(tree, tree[i].childrens);使用apply,它允许我调用一个函数,在本例中为Array.push,它接受tree上任意数量的参数。所以这条线基本上变成了tree.push(child0, child1, ... childn);

所以现在CCD_ 7已经增加了当前子代上的子代的数量。

最简单的解决方案是只使用一个基本的递归函数:

function traverse(parent, visit) {
    var ii;
    visit(parent.name);
    for (ii = 0; ii < parent.children.length; ii += 1) {
        traverse(parent.children[ii], visit);
    }
}

其中,parent的初始值是McDuffFamilyvisit是一个函数,它在访问节点时执行您想执行的任何操作。

此函数将返回家谱中给定名称的所有后代:

function getDescendants(family, name)
{
     var result = [];
     var iterate = function(node, isDescendant)
     {
         if(isDescendant)
             result.push(node.name);
         else
             isDescendant = (node.name == name);
         for(var i=0; i<node.children.length; i++)
             iterate(node.children[i], isDescendant);
     };
     iterate(family, false);
     return result;
}

它将返回一个数组,该数组包含所有子体的名称。

附言:我写的是children而不是childrens,因为children已经是复数了。

for(var names = [], i = 0, l = McDuffFamily.childrens.length; i < l; i++) {
    names.push(McDuffFamily.childrens[i].name);
}
names; // ['Jack McDuff II', 'Poor bastard']

如果你正在使用一个允许[].reduce的环境(比如Node或MooTools(,你也可以这样做:

names = McDuffFamily.childrens.reduce(function(prev, curr) {
    prev.push(curr.name);
}, []);
names; // ['Jack McDuff II', 'Poor bastard']

我认为[].reduce看起来更好,但它对更费力