quirky arguments

The humble "arguments" variable that always exists inside a function call in JavaScript has demonstrated some unexpected behaviour today. This makes me really puzzled because I can not find anything in the ECMA-262 specification that mandates the behaviour – yet all browsers do the same thing in a very obscure corner of their implementations.. Why do we all implement it that way if we weren't explicitly instructed to by the specification?

Here is the issue in a minimal snippet of JavaScript:

function test(){}

test.arguments='something';

test();

alert(test.arguments); // test.arguments is now null ??

so..? Inside the function body we have a local variable called "arguments", but this variable also becomes a property of the function itself, and is subsequently reset to null. Consider

function test(){ alert(arguments==test.arguments); }

which says "true" and shows us that the local variable and the function property refer to the same object.

Some side-effects of this implementation include:

  • "arguments" is a reserved word as function property name, it can not be used
  • We can work out whether a function has been called by a script or not! Consider
    Function.prototype.arguments=true;
    function test(){};
    .
    . /* function definitions and calls here */
    .
    var testWasCalled = ! test.arguments;

    "testWasCalled" is now true if and only if the script has used the "test" function during its execution. Might be a handy trick for trying to optimise large scripts ๐Ÿ˜‰

..but where in the spec is this specified? In other words, is it a bug or a feature?

Advertisements

11 thoughts on “quirky arguments

  1. Exactly what is JavaScript? Does ECMA-262 actually define JavaScript, or does it merely attempt to document what JavaScript is? When implementations differ from ECMA-262, is ECMA-262 outdated or are the implementations wrong?Or is JavaScript something else? Wikipedia says, "JavaScript is the name of Netscape Communications Corporation's implementation of the ECMAScript standard".Here's what ECMA-262 says:"This ECMA Standard is based on several originating technologies, the most well known being JavaScript (Netscape) and JScript (Microsoft).""This Standard defines the ECMAScript scripting language."At least the situation is better than it is with Python, Perl, Ruby, and PHP.

  2. @unfortunately: it's only "Function.arguments" that was deprecated. The "arguments" property of a function's execution context is not deprecated, and is part of ECMAScript: it's defined in ECMA 262 section 10.1.8. I think the original question was not "Where is 'arguments' specified in the standard" but "Where is it specified that it should exhibit this behaviour" – that is, why does test.arguments have its value reset to null after the invocation of test.My guess is that it's something to do with the setting up of function code's execution context (ECMA 262 section 10.2.3), but I don't have the time to bend my head around the specification today.However: the Mozilla documentation states that it is an error to attempt to access the "arguments" property outside of a function declaration. So the code given has, by definition, unspecified behaviour, which is why it's not specified anywhere ๐Ÿ™‚

  3. Interesting find.Btw.

    Array.prototype.makeMeSmile=":D";
    alert(function(){return (arguments.makeMeSmile)}())

    Try it in Opera ๐Ÿ™‚

  4. Your test doesn't work in Firefox 2 and IE 7.In those browsers (didn't check others), it seems you cannot really change the arguments property of a function, and it remains null, whether you call it or not.

  5. I'm voting for spec violation. Ecma 262 section 10.1.6 says:"When control enters an execution context for function code, an object called the activation object is created and associated with the execution context. The activation object is initialised with a propertywith name arguments and attributes { DontDelete }. The initial value of this property is the arguments object described below.The activation object is then used as the variable object for the purposes of variable instantiation."So, the arguments variable inside a function call should share the scope of any variabled declared inside the function call. If function locals were in the same scope as arguments that would mean this shoul alert true: function foo() { var test = true; alert(foo.test == "asdf");}It doesn't, it's undefined. So either, the local is in the wrong scope, or arguments is in the wrong scope. Either way it's a bug.

  6. @hallvors: splintor is right, try this:

    javascript:function test(){};test.arguments='something';alert(test.arguments);test();alert(test.arguments);
    //Opera:
    // -> something
    // -> null
    // FF & IE6:
    // -> null
    // -> null
  7. _Grey_: "the arguments object should not inherit from Array" is a known bug (we found it because some prototype/Script.aculo.us stuff ran into it).splintor: interesting. Basically what IE and Firefox do is to have a readOnly Function.arguments property, returning "null" unless the function is running and pointing to the local arguments object when it does…looking at some of the stranger code in this script:http://www.banquedirecte.fr/include/FormCheck.jsyou can also see the related Netscape JS feature of referencing arguments of a function directly with a function[n] syntax. Look for stuff like

    function warnEmpty (theField, s)
    {   theField.focus()
    	if (arguments.caller.length == 5) {
    		alert(arguments.caller[4]);
    	} else {
    		alert(mPrefix + s + mSuffix);
    	}
        return false
    }

    arguments.caller[4] ? Weird, weird.. Luckily IE doesn't support that so we've been spared seeing this stuff widely used ๐Ÿ™‚

  8. @hallvors: Actually, I think it is good it inherits from Array.I don't really see a reason for not using "arguments" as a fully qualified Array. Of course, I'd rather see an "Arguments" object from which "arguments" inherit, but this is a temporary "fix". I think "arguments" should be mutable, though…This creates apparent problems, of course, as

    for(argument in arguments)

    would do strange things if

    Array.prototype.property = "value"

    (which is probably why you got problems with the mentioned JS libraries), but I'd consider this a weakness of the language anyways (is it that hard to implement a way of marking a property "dontEnum"?)…

    arguments.caller[4] ? Weird, weird.. Luckily IE doesn't support that so we've been spared seeing this stuff widely used ๐Ÿ™‚

    Imho I read somewhere on bugzilla that they just deprecated it in favor of the IE-version: "caller" is not a property of "arguments", but rather of the function (or something like that). Regarding the weird caller[4] syntax, I think IE doesn't understand any of that.

  9. ECMA-262 1st edition, 15.3.5.3:"The value of the arguments property is normally null if there is no outstanding invocation of the function in progress (that is, the function has been called but has not yet returned). When a non-internal Function object (15.3.2.1) is invoked, its arguments property is โ€œdynamically boundโ€ to a newly created object that contains the arguments on which it was invoked (see 10.1.6 and 10.1.8). Note that the use of this property is discouraged; it is provided principally for compatibility with existing old code."From ECMA-262 1st edition, 10.1.6:"If the function object being invoked has an arguments property, let x be the value of that property; the activation object is also given an internal property [[OldArguments]] whose initial value is x; otherwise, an arguments property is created for the function object but the activation object is not given an [[OldArguments]] property.""When a value is to be returned from the call to a function, its activation object is no longer needed and may be permanently decommissioned. At this time, if the activation object has no [[OldArguments]] property, then the arguments property of the function object is deleted; otherwise, the value of the [[OldArguments]] property of the activation object is stored into the arguments property of the function object (an arguments property is created for the function object if necessary)."Of course, all of this was removed in 1998.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s