Array.prototype.slice.call(arguments)和Array.apply(null, arguments)之间的区别

4
据我所知,这两个函数的行为方式相同:
function returnArgs() { return Array.prototype.slice.call(arguments) };

function returnArgs2() { return Array.apply(null, arguments) };

我看到SO上提到这两种方法,但仍不真正理解为什么要使用其中一种。这是出于个人偏好,还是有更实际的原因在起作用?也许我漏掉了一个显而易见的区别?
1个回答

4
第二种方法非常危险,而且并不总是可行的。请尝试以下方法:
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 的,但代码分析问题并不依赖于运行时。JDK 8 中的新运行时 Nashorn 有一个非常不同的优化方法,但我强烈怀疑错误使用 arguments 的净效果是相似的。


“危险”可能有点过了 :) - Pointy
好的,哇,是的,长度为1的数组会破坏它。知道了 :) - i_made_that
@Pointy为了解决这个问题,你可以像这样做:returnArgs2()函数吗?{return arguments.length === 1 ? [arguments[0]] : Array.apply(null, arguments) }; - David Chase
@DavidChase 是的,那会起作用。我将使用我最近阅读的内容更新这个答案。 - Pointy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接