Array.prototype.slice.call(arguments)和Array的区别.应用(null,参数)

Difference between Array.prototype.slice.call(arguments) and Array.apply(null, arguments)

本文关键字:Array 应用 null 参数 区别 slice arguments prototype call      更新时间:2023-09-26

据我所知,这两个函数的行为是相同的:

function returnArgs() { return Array.prototype.slice.call(arguments) };
function returnArgs2() { return Array.apply(null, arguments) };

我看到这两种方法在SO中都被引用,但仍然不明白为什么要使用其中一种而不是另一种。是偏好,还是有更实际的因素在起作用?也许我忽略了一个明显的区别?

第二种方法非常危险,并不总是有效。试一试:

console.log(returnArgs2(3));

将显示一个长度为3的空数组。Array构造函数将单个数字参数解释为需要该长度的数组。

编辑本;作为更新,基于一些关于优化的有趣信息,如果这里有一个"危险"的事情,那就是arguments对象的"泄漏"。根据那篇文章,从函数中传递arguments会使函数代码的分析变得非常困难,因为arguments对象非常奇怪。如果你想防止这种情况发生,安全的做法是:

function returnArgs() {
  var rv = [];
  for (var i = 0; i < arguments.length; ++i)
    rv.push(arguments[i]);
  return rv;
}

引用arguments.length是可以的,引用arguments对象的属性是与实际参数相对应的整数也是可以的。不幸的是,"更漂亮"的函数式方法打败了优化器,但这并不奇怪。

arguments对象的"奇怪"之处在于它为实际参数提供了别名。例如:

function foo(a, b) {
  arguments[1] = a;
  return b;
}
alert(foo("hello", "world")); // "hello"

arguments[1]赋值与对参数变量b直接赋值具有完全相同的效果,反之亦然。因此,如果arguments对象从函数中"转义",静态分析代码不知道参数(本质上与局部变量相同)可能会发生什么,因此它只是放弃并让函数进行解释。

请注意,那篇优化器论文是关于V8的,但代码分析的问题与运行时无关。Nashorn, JDK 8中的新运行时,有一个非常不同的优化方法,但我强烈怀疑误用arguments的净效果是相似的。