The magical world of the JavaScript arguments object
So, I’ve known for a long time that the arguments
object that is available in a function is
a bit “odd”, but until recently I didn’t realize how odd.
Last weekend, I was up in the northeast visiting friends and taking a little break from the south. As I waited at the airport for my flight home, I was browsing Hacker News for anything interesting, waiting for my zone to be called for boarding. I ended up at this guys blog where he was talking about adding contract-like tests to javascript using some extension macros thanks to Sweet.js.
Soon, I was on the plane and with nothing really to do and my chromebook in my carry-on I decided to do some expermentations with some different vanilla-js syntaxes for doing the same thing. Nothing serious, just wanted to play around.
However, I quickly stumbled onto something that I kind of blew my mind.
Here is a extremely simplified version what I did:
1 | var clean = function(expected) { |
If expected
is not a function then I wanted to wrap it into a function, and
returning the original value that was given in it’s place.
Now, it’s not the greatest example of idomatic javascript that I’ve ever written, but in my defense I was hurltleing through the air at 500mph in a box with wings.
So, I tried passing it a function:
1 | var fn = clean(function() { return 1; }); |
Cool, but then I tried it with something that wasn’t a function:
1 | var fn = clean(1); |
I expected the return of fn()
to be 1
. However, much to my surprise, I got
a reference back to fn
itself… “Huh?” my former self though. I opened
up the developer console, and added a breakpoint inside clean
. Shockingly – at least to
me at the time – was that capturedArugments[0]
did not point at the value
I originally had passed in… Instead it pointed at the function that I had
assigned to expected
.
(mindblown)
I had a feeling that I had stumbled onto something that I should have been aware of a long time ago. I wrote another function, something even simplier, in an attempt to understand what was going on.
1 | var strangeAdd = function(x,y) { |
And no matter what numbers that I fed into the function, the result would always come back 15
. In fact, no
matter what data-type or object I fed in, I would always get 15
. Even more specifically, the only way
that I would not get back 15
, was when I invoked the function with less than two arguments, eg.
strangeAdd(); // NaN
.
Then I tried something else.
1 | var strangeAdd = function(x,y) { |
And lo-and-behold, the same result. It appeared like the arguments
object
and the variables of the function are linked. Change one and it effects the other.
By this time, I was off the plane and was able to reconnect the internets – my
source of information, and was able to find that this is a fairly well documented
“feature” of the arguments
object. I just had never heard of it.
(mindblown)
Note that this behavior is no longer supported when in strict mode:
1 | var noMoreMonkeyBusiness = function(x,y) { |
Phew… Sanity.
I’m really not sure when one would ever want to do this, but I’m sure some where in some code base this trick is used. But I’m more surprised that I just had never heard of it until now!