Mysterious arguments object assignments
This past week, I found what I thought was a bug in Firefox’s JavaScript implementation and filed it. A response from Brendan Eich indicated that the behavior in question was, in fact, compliant with the spec and had been implemented for some time. I ran a few more tests to try and figure out where I had gone wrong. Indeed, Firefox, Internet Explorer, and Safari all exhibited the same behavior while Chrome did not. Here’s what happened.
The code
The code in question is as follows:
function doAdd(num1, num2) {
if(arguments.length == 1) {
arguments[1] = 10;
}
alert(arguments[0] + num2);
}
doAdd(10);
What would you expect the bottom line to output? In Chrome, it outputs 20, because assigning to arguments[1] also assigns to num2. In the other browsers, it outputs NaN, because assigning to arguments[1] does not also assign to num2. What exactly is going on here?
The spec
My confusion stemmed from Section 10.6 Note 1 of ECMA-262, 5th Edition, which reads:
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.
I’ve discussed the similar clause before, at least the 3rd edition one, when answering Baranovskiy’s JavaScript quiz. I thought I had understood that arguments was always bound to the named arguments of the function. Both Tom Schuster and Brendan Eich pointed out that earlier in Section 10.6, in the instructions for creating the arguments object, the following appears:
args the actual arguments passed to the [[Call]] internal method
1. Let len be the number of elements in args.
…
10. Let indx = len – 1.
11. Repeat while indx >= 0,
So the arguments object is created based on the number of actual arguments passed into the function and not on the number of named parameters defined for the function. That means, as Tom pointed out, the setter that would be created for the numeric index of the arguments object only applies to the number of arguments that were actually passed in. In my example, therefore, arguments[1] becomes a straight property assignment to the arguments object rather than calling the special setter that would copy the value to the named argument.
More code
So even though my previous example wouldn’t work in all browsers, this one will:
function doAdd(num1, num2) {
arguments[1] = 10;
alert(arguments[0] + num2);
}
doAdd(10, 25); //20
The last line of this example outputs 20 in all browsers. Since I’m now passing in two arguments to the function, that means the arguments object is being created with two slots and therefore the special setter works for both indices 0 and 1. Setting arguments[1] in this code actually does update num2 and overwrites the value that was passed in.
Conclusion
Specifications are difficult to understand and even more difficult to implement. This was just a subtle reminder that there are dark corners of JavaScript where dragons lie. It’s fun to poke the dragons from time to time and learn exactly what they’ll do. Sometimes they’ll burn you, but you’ll learn either way.
Disclaimer: Any viewpoints and opinions expressed in this article are those of Nicholas C. Zakas and do not, in any way, reflect those of my employer, my colleagues, Wrox Publishing, O'Reilly Publishing, or anyone else. I speak only for myself, not for them.
Both comments and pings are currently closed.




8 Comments
very good point
i had the impression that arguments array can’t be modified
abhijeet on November 2nd, 2010 at 10:24 am
Seems like everyday you can learn something new about javascript. Thanks for keeping us little guys informed.
Arlo Carreon on November 2nd, 2010 at 12:00 pm
Lesson: don’t rely on argument changes affecting named parameters. Good to know!
Steve Clay on November 2nd, 2010 at 5:33 pm
Just curious. Have you filed a bug with Chrome, since that implementation is the broken one?
2nd question. Is this covered in the ECMAScript conformance test suite? Otherwise it probably needs a bug report as well.
Lars Gunther on November 2nd, 2010 at 6:35 pm
Never mind question one. I’ve found the Chrome bug.
Lars Gunther on November 2nd, 2010 at 6:37 pm
An other item on the Chrome issue list is also interesting. It also is about the arguments object (array?)
an other Chorme bug
Jays on November 3rd, 2010 at 5:05 am
Nicholas,
I am interested in knowing why you would be using the arguments array in this example. It seems like the ‘num2′ variable would be a better choice. Were you just exploring JavaScript or is there a method behind the madness that I am missing?
-matt
matt snider on November 3rd, 2010 at 11:55 am
@Matt – No, this is purely madness. I generally don’t like using the
argumentsat all, as I think it obscures the meaning of data that’s being passed in. This was just a quick demo that I came up with to test what was going on.Nicholas C. Zakas on November 3rd, 2010 at 9:33 pm
Comments are automatically closed after 14 days.