arguments.slice() 应该在 ES5 中工作吗?

Should arguments.slice() work in ES5?

我正在为我看 Crockford on Javascript - Act III: Function the Ultimate at around 41 mins 26 seconds. The code on his screen uses arguments.slice() in a way that causes an error

function curry(func){
    var args = arguments.slice(1);
    ...
}

他是这样解释的:

I'll first get an array of arguments, except the first one, because the first one is a function and I don't need that one. In this case I'm assuming I'm on ES5, so I'm not doing the awful Array.prototype.apply() trick.

问题是 运行 arguments.slice() 导致此错误:

Uncaught TypeError: arguments.slice is not a function

我正在测试肯定有 ES5 的现代浏览器!让代码正常工作的唯一方法是使用一些 "awful" 技巧(他这样称呼它们),例如Array.prototype.slice.apply(arguments, [1])[].slice.call(arguments, 1);

他只是误会了吗?他的幻灯片有错别字吗?为什么 arguments.slice() 在我的 ES5 浏览器中不起作用?

arguments 对象不是数组。它类似于Array(Array like),但除了length之外没有任何Array属性。

您必须先使用上述技巧将其转换为数组。

var slice = Array.prototype.slice;
function curry(func){
    var args = slice.call(arguments, 1); // converts into array
}

参数将继承数组的所有原型方法,但在最终草案中删除了此功能。

https://mail.mozilla.org/pipermail/es5-discuss/2009-August/003112.html

I implement the logic to make the Arguments object inherit from Array in WebKit last friday and it's quickly turned up a severe
incompatibility with Prototype.js ... This breaks at the very least a number of Apple sites and Nasa.gov -- ... Due to these site breakages, caused by a major compatibility problem
in a fairly major library it seems infeasible to attempt to retrofit
array like behaviour onto arguments.

所以最后,他们没有强迫每个人更改代码以避免破坏网页,而是恢复了此更改。因此,即使在 ES5 中,您仍然需要应用上述技巧将参数转换为实际数组。

Quoting TC39 成员 Allen Wirfs-Brock:

Until very late in the development of ECMAScript 5, argument object were going to inherit all of the Array.prototype methods. But the "final draft" of ES5 approved by TC39 in Sept. 2009 did not have this feature.

让arguments对象继承自Array原型其实是有计划的,但是付诸实践的时候broke the web。因此,在正式发布之前,它已从最终修订版中删除。


如今,随着 ECMAScript 2015 (a.k.a.ES6) 标准化,最好的方法是使用 rest parameters:

function curry(func, ...args) {
  // ...
}

相当于ES5:

function curry(func) {
  var args = [].slice.call(arguments, 1);
  // ...
}

此功能已在 Firefox 和 Edge 中原生可用,如果您使用 JavaScript 编译器(例如 Babel.

,则随处可用

因为arguments是一个类数组,你可以使用:

function fn() {
  const args = Array.from(arguments)
}

(如果你有 Polyfill or Babel