在多个对象上下文中调用同一个函数

Calling same function in multiple object's context?

本文关键字:调用 同一个 函数 上下文 对象      更新时间:2023-09-26

我有一个像这样的对象结构;

{
   this.parent = undefined;
   this.children = [];
}

children中的所有值都具有与上面相同的结构,除了它们的parent将是对以其为子对象的对象的引用。

我怎么能很容易地迭代所有的孩子等,但在孩子的对象上下文中?

我知道如何循环一个对象的子对象

obj.children.forEach(function(child) {
});

但是我如何迭代所有子节点的子节点,当子节点可以进入10-20-30深度继承时?

使用递归

function deepForEach(node, fn) {
    fn(node);
    node.children.forEach(function(child) {
        deepForEach(child, fn);
    });
}
deepForEach(obj, function(obj) {
    console.log(obj);
});

如果我们用简单的英语来描述它,它的工作方式就变得很明显了:

  • 如果没有子节点,只需调用该节点的回调函数。(基本情况)
  • 如果有孩子,先自己处理,然后再为每个孩子做整个程序。

这种递归称为预序遍历。

我们将编写一个递归函数。递归表示它将再次执行自身:

function iterate(obj) {
    // we will write the parent and the name
    console.log(obj.parent + ' | ' + obj.name);
    // if it has children
    if (obj.children.length) {
        // for each child
        for (var i = 0, l = obj.children.length; i < l; i++) {
            // we will call this function again
            arguments.callee(obj.children[i]);
        }
    }
}

现在如果我们有一个这样的对象:

var obj = {
    name: 'P1',
    parent: undefined,
    children: [
        {
            name: 'P2',
            parent: 'P1',
            children: []
        },
        {
            name: 'P3',
            parent: 'P1',
            children: [
                {
                    name: 'P4',
                    parent: 'P3',
                    children: [
                        {
                            name: 'P5',
                            parent: 'P4',
                            children: []
                        }
                    ]
                }
            ]
        },
        {
            name: 'P6',
            parent: 'P1',
            children: []
        }
    ]
};

我们可以遍历它:

iterate(obj);

FIDDLE DEMO(在浏览器中打开控制台)

标准方法是像icktofay建议的那样使用递归。

在这种处理中有一点更烦人的是如何管理"块"中的遍历(例如,如果你想在javascript程序的"后台"中使用计时器)。

在这种情况下,可以使用显式堆栈:

function process_tree(root_node,
                      process_node,
                      chunk_size,
                      completion_call)
{
    var todo = []; // nodes that need processing
    function processOneChunk() {
        for (var j=0; todo.length && j<chunk_size; j++) {
            var x = todo.pop();
            process_node(x);
            for (var i=0; i<x.children.length; i++) {
                todo.push(x.children[i]);
            }
        }
        if (todo.length) {
            setTimeout(processOneChunk, 0);
        } else {
            completion_call();
        }
    }
    todo.push(root_node);
    setTimeout(processOneChunk, 0);
}