What is the rationale behind this behaviour?
function f(x) {
console.log(arguments[0]);
x = 42;
console.log(arguments[0]);
}
f(1);
// => 1
// => 42
Altering x
is reflected in arguments[0]
because indexes of arguments
may be getter/setters for the matching named argument. This is defined under step 11.c.ii of 10.6:
Add name as an element of the list mappedNames.
Let g be the result of calling the MakeArgGetter abstract operation with arguments name and env.
Let p be the result of calling the MakeArgSetter abstract operation with arguments name and env.
Call the [[DefineOwnProperty]] internal method of map passing ToString(indx), the Property Descriptor {[[Set]]: p, [[Get]]: g, [[Configurable]]: true}, and false as arguments.
As noted in the steps above that, this requires that strict is false and, in this case, that f
is called with a value for x
:
f() // undefined, undefined (no argument, no getter/setter)
f(1) // 1, 42
Actually, in strict mode, this does not happen as you can see here.
If you read section 10.6 of the ECMA Standard, in particular Note 1, you'll see:
For non-strict mode functions the array index (defined in 15.4) named data properties of an arguments object whose numeric name values are less than the number of formal parameters of the corresponding function object initially share their values with the corresponding argument bindings in the function‘s execution context. This means that changing the property changes the corresponding value of the argument binding and vice-versa. This correspondence is broken if such a property is deleted and then redefined or if the property is changed into an accessor property. For strict mode functions, the values of the arguments object‘s properties are simply a copy of the arguments passed to the function and there is no dynamic linkage between the property values and the formal parameter values.
In short, what this is saying is that, in non-strict mode, named function parameters operate as aliases for items in the arguments
object. Thus, changing the value of a named parameter will change the value of the equivalent arguments
item and vice versa. This is not a mistake. This is expected behaviour.
As an editorial, it's probably not a good idea to rely on this behaviour as it can lead to some very confusing code. Also, such code, if executed in strict mode, would not longer work.