【问题标题】:Recursive Function.prototype.apply conceptual understanding递归 Function.prototype.apply 概念理解
【发布时间】:2016-07-17 12:40:18
【问题描述】:

我遇到了 this stackoverflow question 关于递归展平 JS 数组的问题。这是公认的答案:

function flatten() {
    var flat = [];
    for (var i = 0; i < arguments.length; i++) {
        if (arguments[i] instanceof Array) {
            flat.push.apply(flat, flatten.apply(this, arguments[i]));
        } else {
            flat.push(arguments[i]);
        }
    }
    return flat;
}

flatten([[1], 2, [3, 4]]); // returns [1, 2, 3, 4]

我无法理解 flat.push.apply(...)flatten.apply(...) 的工作原理。

我知道只有当数组中的 none 项是数组本身时,该函数才会退出。我也了解Function.prototype.apply() 允许您使用参数数组调用函数。

我不明白为什么你使用flat.push... 如果flat 将在每次函数迭代中设置为[]。另外,将flat 设置为this 上下文有什么意义?

有人可以帮助解释flat.push.apply(flat, flatten.apply(this, arguments[i])); 的执行是如何工作的吗?

【问题讨论】:

  • "如果 flat 在每次函数迭代时都设置为 []" - 这不是迭代,而是递归。每个调用都有自己的局部变量。
  • flat设置为this上下文有什么意义?”——这是push方法的上下文,即将被推送的数组。就像你定期调用flat.push(…) on flat
  • flat 不是每次迭代都设置,它只设置一次,在循环之前。
  • 那么递归的执行栈是如何工作的,它与迭代的执行栈有什么不同呢?
  • 为什么? r=[];r.push([1]);r; 生成[[1]],而r=[];r.push.apply(r,[1]);r; 生成[1]

标签: javascript arrays recursion


【解决方案1】:

他安全地使用flat.push,因为push实际上每次都在不同的数组上调用。每次flatten 执行时,它都会创建一个新数组,该数组具有不同的引用存储在flat 变量中,因此每个递归都与不同的flat 数组相关联。

flat 设置为this 上下文提供了要在其上调用push 的数组。尝试将其设置为null,您可能会因为非法操作而得到TypeError - 尝试在null 上调用push

现在是更复杂的部分。 push 接受要添加到数组的参数列表,对吗?但是有时不方便一一提供这些参数,特别是如果您不知道push 应该收到多少个参数,就像您的情况一样,要展平的数组的大小会有所不同。

这就是为什么该代码的作者通过 apply 调用 push 并将数组引用作为第二个参数 - 这是 flatten.apply(this, arguments[i]) 的返回值 - 到那时引用仅包含数字的数组。该数组的每个数字都被推送到flat,因为apply 调用push 并通过参数将该数组的整个数字列表传递给push

flatten.apply(this, arguments[i]) 部分是通过apply 调用的,原因类似——它利用arguments(每个函数具有的类似数组的对象)轻松处理函数参数。在apply 的第一个参数中移交this 在这里并不重要,因为flatten 中的this 没有用处(this 指向代码示例中的全局对象)。

【讨论】:

    猜你喜欢
    • 2014-12-23
    • 1970-01-01
    • 1970-01-01
    • 2018-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-06
    相关资源
    最近更新 更多