问题
I think it is an old Javascript behavior (Crockford said it is a design error) that inside a function, arguments
is like an array, except it is not a real array, so array methods cannot be invoked on it:
function foo() { console.log(arguments.slice(1)) } // won't work
foo(1,2,3);
And I just tried it on the latest Firefox and Chrome, and it won't work on both. So we may have to use
function foo() { console.log(Array.prototype.slice.call(arguments, 1)) }
foo(1,2,3);
But why not make arguments
a real array in the modern JavaScript? There probably shouldn't be any program that depends on arguments
not being a real array? What might be a reason not to make it a real array now?
One reason I can think of is, if programmers start treating it as an array, then the code won't work in older browsers, but there are other things in ECMA-5 that won't work in older browsers too.
回答1:
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.
In August 2009, Oliver Hunt of Apple posted this to the the es5-discuss mailing list
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.
The rest of TC39 agreed with Oliver's assessment and the feature was removed from the final draft.
Perhaps, such code has disappeared sufficiently from the web that the proposed ES5 solution would work today. However, it doesn't matter because rest parameters in ES6 is a better solution to the problem and a completely new syntactic feature that can't have any backwards compatibility issues with existing code.
回答2:
There are sites online that rely upon arguments
not being an array, such as those using older versions of Prototype and script.aculo.us. This means that any browser that changed it (ES4 included this, and it was implemented along with numerous other parts in Futhark, used in Opera from 9.5–10.10) would break these sites, and there's a strong market encouragement to not break sites (any browser that breaks websites will not get used by users who care about those sites for obvious reasons, given many sites are rarely updated).
回答3:
It is mainly because it needs to be read-only as far as I can deduct.
If it were an array, then it needs to be a read-only array which means that we have to get rid of push, pop, splice etc... any method that modifies the array. By this point, even though I agree other methods like slice might come handy but it's already a data structure that has different requirements than javascript Array.
I think they shouldn't have said it is an array-like object, in my view, it is just a different object that happened to have a property called length (same as Array).
回答4:
what prevents modern implementation not to treat arguments as a real array?
Implementations of what? The EcmaScript 5.1 specification, yes. Yet there is quite accurate specified that there should be an arguments binding and what such an Arguments object is.
Also, an Arguments
object just is not a real Array
, as it has some very special behaviour regarding its properties. [[Get]], [[Delete]] etc are overwritten to reflect the function argument variables. Calling push
, splice
etc on such an object if it were an array could cause havoc.
回答5:
In the next version of ECMAScript, this issue (and several others) is being addressed with rest parameters.
function foo(...rest) {
console.log(rest.slice(1))
}
foo(1, 2, 3);
Unlike arguments
, rest parameters will be real arrays, so this will work.
Rest parameters can do even more. In the above example you probably wanted to use the first argument for one thing and everything after it for something else. You could do this instead:
function foo(first, ...rest) {
console.log('first: ', first);
console.log('rest: ', rest);
}
foo(1, 2, 3);
This will log:
first: 1
rest: [ 2, 3 ]
The proposal: http://wiki.ecmascript.org/doku.php?id=harmony:rest_parameters
来源:https://stackoverflow.com/questions/13184799/for-javascript-what-prevents-modern-implementation-not-to-treat-arguments-as-a