2016-03-29 106 views
0

我遇到this stackoverflow question关于递归平展JS数组。这里是公认的答案:递归Function.prototype.apply概念理解

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(...)工作。

据我所知,该函数只有在数组中的项为时才会退出。我也明白Function.prototype.apply()允许你使用一个参数数组来调用一个函数。

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

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

+0

“* if'flat'将在每个函数迭代中设置为'[]'*” - 它不是迭代,它是递归。每个调用都有自己的局部变量。 – Bergi

+0

“*设置'flat'作为这个上下文有什么意义?*” - 这是'push' *方法的上下文,它是将被推入的数组。就像您经常在'flat' *上调用'flat.push(...)'*一样。 – Bergi

+0

'flat'每次迭代都没有设置,它只在循环之前设置一次。 – dandavis

回答

2

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

设置flat作为this上下文提供了一个名为push的数组。尝试将其设置为null,由于非法操作,您可能会获得TypeError - 尝试拨打push,null

现在为更复杂的部分。 push接受要添加到数组的参数列表,对吗?但是,有时候不方便逐一提供这些参数,尤其是,如果您不知道,有多少个push应该接收,就像在您的情况中一样,阵列的扁平尺寸会有所不同。

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

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