又一个Call vs Apply查询

Har*_*ish 2 javascript

当我尝试运行以下代码时:

function flatten(a) {
  return [].slice.call(arguments).reduce(function(acc, val) {
    return acc.concat(Array.isArray(val) ? flatten.call(null, val) : val);
  }, []);
}
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

未捕获RangeError:超出最大调用堆栈大小

但如果我使用flatten.apply而不是flatten.call,它的工作完美.(深度压平输入数组).

除了这个link1link2之外,我还阅读了其他一些博客和文章,以了解其行为的原因.我要么找不到答案,要么就是忽略了它.(原谅我的眼睛,如果在后一种情况下)

当然,这两者之间的根本区别在于:

apply - 要求可选参数为数组

call - 要求显式列出可选参数

通常,函数可以采用任何类型的参数 - 基元和非基元.所以,我的问题是:

  1. 调用方法的可选参数之一可以是类型Array还是其他非基本类型?

  2. 为什么上面的代码超过了调用堆栈,何时call使用?

编辑:由于call使用了2 种方法,我的描述含糊不清.我做了修改以澄清.

geo*_*org 7

你的错误在这里:

[].slice.call(arguments).reduce
              ^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)

所以,当你通过[x],你调用reduce[[x]]和第一val[x].然后你flatten再次打电话[x],故事重演.

另一方面,apply(..., val)将仅传递xflatten,从而将嵌套级别减少一个.

如果您对如何使用apply扁平深层嵌套数组感兴趣,可以不使用递归:

while(ary.some(Array.isArray))
  ary = [].concat.apply([], ary);
Run Code Online (Sandbox Code Playgroud)

这是callvs 的一个小例子apply:

function fun() {
  var len = arguments.length;
  document.write("I've got " 
                 + len 
                 + " " 
                 + (len > 1 ? " arguments" : "argument")
                 + ": " 
                 + JSON.stringify(arguments)
                 + "<br>");   
}

fun.call(null, 123);
// fun.apply(null, 123); <-- error, won't work

fun.call(null, [1,2,3]);
fun.apply(null, [1,2,3]);
                    
                    
Run Code Online (Sandbox Code Playgroud)