ECMA-262-3 in detail. Chapter 5. Functions.

Read this article in: Russian, Chinese (version 1, version 2).

In this article we will talk about one of the general ECMAScript objects — about functions. In particular, we will go through various types of functions, will define how each type influences variables object of a context and what is contained in the scope chain of each function. We will answer the frequently asked questions such as: “is there any difference (and if there are, what are they?) between functions created as follows:

var foo = function () {
  ...
};
 

from functions defined in a “habitual” way?”:

function foo() {
  ...
}
 

Or, “why in the next call, the function has to be surrounded with parentheses?”:

(function () {
  ...
})();
 

Since these articles relay on earlier chapters, for full understanding of this part it is desirable to read Chatper 2. Variable object and Chapter 4. Scope chain, since we will actively use terminology from these chapters.

But let us give one after another. We begin with consideration of function types.

In ECMAScript there are three function types and each of them has its own features.

A Function Declaration (abbreviated form is FD) is a function which:

  • has an obligatory name;
  • in the source code position it is positioned: either at the Program level or directly in the body of another function (FunctionBody);
  • is created on entering the context stage;
  • influences variable object;
  • and is declared in the following way:
function exampleFunc() {
  ...
}
 

The main feature of this type of functions is that only they influence variable object (they are stored in the VO of the context). This feature defines the second important point (which is a consequence of a variable object nature) — at the code execution stage they are already available (since FD are stored in the VO on entering the context stage — before the execution begins).

Example (function is called before its declaration in the source code position):

foo();
 
function foo() {
  alert('foo');
}
 

What’s also important is the position at which the funcion is defined in the source code (see the second bullet in the Function declaration definition above):

// function can be declared:
// 1) directly in the global context
function globalFD() {
  // 2) or inside the body
  // of another function
  function innerFD() {}
}
 

These are the only two positions in code where a function may be declared (i.e. it is impossible to declare it in an expression position or inside a code block).

There’s one alternative to function declarations which is called function expressions, which we are about to cover.

A Function Expression (abbreviated form is FE) is a function which:

  • in the source code can only be defined at the expression position;
  • can have an optional name;
  • it’s definition has no effect on variable object;
  • and is created at the code execution stage.

The main feature of this type of functions is that in the source code they are always in the expression position. Here’s a simple example such assignment expression:

var foo = function () {
  ...
};
 

This example shows how an anonymous FE is assigned to foo variable. After that the function is available via foo name — foo().

The definition states that this type of functions can have an optional name:

var foo = function _foo() {
  ...
};

What’s important here to note is that from the outside FE is accessible via variable foofoo(), while from inside the function (for example, in the recursive call), it is also possible to use _foo name.

When a FE is assigned a name it can be difficult to distinguish it from a FD. However, if you know the definition, it is easy to tell them apart: FE is always in the expression position. In the following example we can see various ECMAScript expressions in which all the functions are FE:

// in parentheses (grouping operator) can be only an expression
(function foo() {});

// in the array initialiser – also only expressions
[function bar() {}];

// comma also operates with expressions 
1, function baz() {}; 
 

The definition also states that FE is created at the code execution stage and is not stored in the variable object. Let’s see an example of this behavior:

// FE is not available neither before the definition
// (because it is created at code execution phase),
 
alert(foo); // "foo" is not defined
 
(function foo() {});
 
// nor after, because it is not in the VO
 
alert(foo);  // "foo" is not defined
 

The logical question now is why do we need this type of functions at all? The answer is obvious — to use them in expressions and “not pollute” the variables object. This can be demonstrated in passing a function as an argument to another function:

function foo(callback) {
  callback();
}
 
foo(function bar() {
  alert('foo.bar');
});
 
foo(function baz() {
  alert('foo.baz');
});
 

In case a FE is assigned to a variable, the function remains stored in memory and can later be accessed via this variable name (because variables as we know influence VO):

var foo = function () {
  alert('foo');
};
 
foo();
 

Another example is creation of encapsulated scope to hide auxiliary helper data from external context (in the following example we use FE which is called right after creation):

var foo = {};
 
(function initialize() {
 
  var x = 10;
 
  foo.bar = function () {
    alert(x);
  };
 
})();
 
foo.bar(); // 10;
 
alert(x); // "x" is not defined
 

We see that function foo.bar (via its [[Scope]] property) has access to the internal variable x of function initialize. And at the same time x is not accessible directly from the outside. This strategy is used in many libraries to create “private” data and hide auxiliary entities. Often in this pattern the name of initializing FE is omitted:

(function () {
 
  // initializing scope
 
})();
 

Here’s another examples of FE which are created conditionally at runtime and do not pollute VO:

var foo = 10;
 
var bar = (foo % 2 == 0
  ? function () { alert(0); }
  : function () { alert(1); }
);
 
bar(); // 0
Notice, ES5 standardized bound functions. This type of functions correctly binds the value of this, making it locked in any function invocation.

var boundFn = function () {
  return this.x;
}.bind({x: 10});

boundFn(); // 10
boundFn.call({x: 20}); // still 10

The most usage bound functions find in attaching them as event listeners, or in postponed (setTimeout) functions, that still should operate on some objects as their this value.

You can get more information on the bound functions in the appropriate chapter from ES5 series.

Let’s go back and answer the question from the beginning of the article — “why is it necessary to surround a function in parentheses if we want to call it right from it’s definition”. Here’s an answer to this question: restrictions of the expression statement.

According to the standard, the expression statement (ExpressionStatement) cannot begin with an opening curly brace — { since it would be indistinguishable from the block, and also the expression statement cannot begin with a function keyword since then it would be indistinguishable from the function declaration. I.e., if we try to define an immediately invoked function the following way (starting with a function keyword):

function () {
  ...
}();

// or even with a name

function foo() {
  ...
}();
 

we deal with function declarations, and in both cases a parser will produce a parse error. However, the reasons of these parse errors vary.

If we put such a definition in the global code (i.e. on the Program level), the parser should treat the function as declaration, since it starts with a function keyword. And in first case we get a SyntaxError because of absence of the function’s name (a function declaration as we said should always have a name).

In the second case we do have a name (foo) and the function declaration should be created normally. But it doesn’t since we have another syntax error there — a grouping operator without an expression inside it. Notice, in this case it’s exactly a grouping operator which follows the function declaration, but not the parentheses of a function call! So if we had the following source:

// "foo" is a function declaration
// and is created on entering the context

alert(foo); // function

function foo(x) {
  alert(x);
}(1); // and this is just a grouping operator, not a call!

foo(10); // and this is already a call, 10

everything is fine since here we have two syntactic productions — a function declaration and a grouping operator with an expression (1) inside it. The example above is the same as:

// function declaration
function foo(x) {
  alert(x);
}

// a grouping operator
// with the expression
(1);

// another grouping operator with
// another (function) expression
(function () {});

// also - the expression inside
("foo");

// etc

In case we had such a definition inside a statement, then as we said, there because of ambiguity we would get a syntax error:

if (true) function foo() {alert(1)}

The construction above by the specification is syntactically incorrect (an expression statement cannot begin with a function keyword), but as we will see below, none of the implementations provide the syntax error, but handle this case, though, every in it’s own manner.

Having all this, how should we tell the parser that what we really want it to call a function immediately after its creation? The answer is obvious. It’s should be a function expression, and not a function declaration. And the simplest way to create an expression is to use mentioned above grouping operator. Inside it always there is an expression. Thus, the parser distinguishes a code as a function expression (FE) and there is no ambiguity. Such a function will be created during the execution stage, then executed, and then removed (if there are no references to it).

(function foo(x) {
  alert(x);
})(1); // OK, it's a call, not a grouping operator, 1

In the example above the parentheses at the end (Arguments production) are already call of the function, and not a grouping operator as it was in case of a FD.

Notice, in the following example of the immediate invocation of a function, the surrounding parentheses are not required, since the function is already in the expression position and the parser knows that it deals with a FE which should be created at code execution stage:

var foo = {
 
  bar: function (x) {
    return x % 2 != 0 ? 'yes' : 'no';
  }(1)
 
};
 
alert(foo.bar); // 'yes'
 

As we see, foo.bar is a string but not a function as can seem at first inattentive glance. The function here is used only for initialization of the property — depending on the conditional parameter — it is created and called right after that.

Therefore, the complete answer to the question “about parentheses” is the following:

Grouping parentheses are needed when a function is not at the expression position and if we want to call it immediately right after its creation — in this case we just manually transform the function to FE.

In case when a parser knows that it deals with a FE, i.e. the function is already at the expression position — the parentheses are not required.

Apart from surrounding parentheses it is possible to use any other way of transformation of a function to FE type. For example:

1, function () {
  alert('anonymous function is called');
}();

// or this one
!function () {
  alert('ECMAScript');
}();

// and any other manual
// transformation

...

 

However, grouping parentheses are just the most widespread and the elegant way to do it.

By the way, the grouping operator can surround the function description as without call parentheses, and also including call parentheses. I.e. both expressions below are correct FE:

(function () {})();
(function () {}());
 

The following example shows a code in which none of implementations processes accordingly to the specification:

if (true) {
 
  function foo() {
    alert(0);
  }
 
} else {
 
  function foo() {
    alert(1);
  }
 
}
 
foo(); // 1 or 0 ? test in different implementations
 

Here it is necessary to say that according to the standard this syntactic construction in general is incorrect, because as we remember, a function declaration (FD) cannot appear inside a code block (here if and else contain code blocks). As it has been said, FD can appear only in two places: at the Program level or directly inside a body of another function.

The above example is incorrect because the code block can contain only statements. And the only place in which function can appear within a block is one of such statements — the expression statement. But by definition it cannot begin with an opening curly brace (since it is indistinguishable from the code block) or a function keyword (since it is indistinguishable from FD).

However in section of errors processing the standard allows for implementations extensions of program syntax. And one of such extensions can be seen in case of functions which appear in blocks. All implementations existing today do not throw an exception in this case and process it. But every in its own way.

Presence of if-else branches assumes a choice is being made which of the two function will be defined. Since this decision is to be made at runtime, that implies that a function expression (FE) should be used. However the majority of implementations will simply create both of the function declarations (FD) on entering the context stage, but since both of the functions use the same name, only the last declared function will get called. In this example the function foo shows 1 although the else branch never executes.

However, SpiderMonkey implementation treats this case in two ways: on the one hand it does not consider such functions as declarations (i.e. the function is created on the condition at the code execution stage), but on the other hand they are not real function expressions since they cannot be called without surrounding parentheses (again the parse error — “indistinguishably from FD”) and they are stored in the variable object.

My opinion is that SpiderMonkey handles this case correctly, separating the own middle type of function — (FE + FD). Such functions are correctly created due the time and according to conditions, but also unlike FE, and more like FD, are available to be called from the outside. This syntactic extension SpiderMonkey names as Function Statement (in abbreviated form FS); this terminology is mentioned in MDC. JavaScript inventor Brendan Eich also noticed this type of functions provided by SpiderMonkey implementation.

In case FE has a name (named function expression, in abbreviated form NFE) one important feature arises. As we know from definition (and as we saw in the examples above) function expressions do not influence variable object of a context (this means that it’s impossible to call them by name before or after their definition). However, FE can call itself by name in the recursive call:

(function foo(bar) {
 
  if (bar) {
    return;
  }
 
  foo(true); // "foo" name is available
 
})();
 
// but from the outside, correctly, is not
 
foo(); // "foo" is not defined
 

Where is the name “foo” stored? In the activation object of foo? No, since nobody has defined any “foo” name inside foo function. In the parent variable object of a context which creates foo? Also not, remember the definition — FE does not influence the VO — what is exactly we see when calling foo from the outside. Where then?

Here’s how it works: when the interpreter at the code execution stage meets named FE, before creating FE, it creates auxiliary special object and adds it in front of the current scope chain. Then it creates FE itself at which stage the function gets the [[Scope]] property (as we know from the Chapter 4. Scope chain) — the scope chain of the context which created the function (i.e. in [[Scope]] there is that special object). After that, the name of FE is added to the special object as unique property; value of this property is the reference to the FE. And the last action is removing that special object from the parent scope chain. Let’s see this algorithm on the pseudo-code:

specialObject = {};
 
Scope = specialObject + Scope;
 
foo = new FunctionExpression;
foo.[[Scope]] = Scope;
specialObject.foo = foo; // {DontDelete}, {ReadOnly}
 
delete Scope[0]; // remove specialObject from the front of scope chain
 

Thus, from the outside this function name is not available (since it is not present in parent scope), but special object which has been saved in [[Scope]] of a function and there this name is available.

It is necessary to note however, that some implementations, for example Rhino, save this optional name not in the special object but in the activation object of the FE. Implementation from Microsoft — JScript, completely breaking FE rules, keeps this name in the parent variables object and the function becomes available outside.

Let’s have a look at how different implementations handle this problem. Some versions of SpiderMonkey have one feature related to special object which can be treated as a bug (although all was implemented according to the standard, so it is more of an editorial defect of the specification). It is related to the mechanism of the identifier resolution: the scope chain analysis is two-dimensional and when resolving an identifier it considers the prototype chain of every object in the scope chain as well.

We can see this mechanism in action if we define a property in Object.prototype and use a “nonexistent” variable from the code. In the following example when resolving the name x the global object is reached without finding x. However since in SpiderMonkey the global object inherits from Object.prototype the name x is resolved there:

Object.prototype.x = 10;
 
(function () {
  alert(x); // 10
})();
 

Activation objects do not have prototypes. With the same start conditions, it is possible to see the same behavior in the example with inner function. If we were to define a local variable x and declare inner function (FD or anonymous FE) and then to reference x from the inner function, this variable would be resolved normally in the parent function context (i.e. there, where it should be and is), instead of in Object.prototype:

Object.prototype.x = 10;
 
function foo() {
 
  var x = 20;
 
  // function declaration  
 
  function bar() {
    alert(x);
  }
 
  bar(); // 20, from AO(foo)
 
  // the same with anonymous FE
 
  (function () {
    alert(x); // 20, also from AO(foo)
  })();
 
}
 
foo();
 

Some implementations set a prototype for activation objects, which is an exception compared to most of other implementations. So, in the Blackberry implementation value x from the above example is resolved to 10. I.e. do not reach activation object of foo since value is found in Object.prototype:

AO(bar FD or anonymous FE) -> no ->
AO(bar FD or anonymous FE).[[Prototype]] -> yes - 10
 

And we can see absolutely the same situation in older SpiderMonkey versions (before ES5) in case of special object of a named FE. This special object (by the standard) is a normal object“as if by expression new Object(), and accordingly it should be inherited from Object.prototype, what is exactly what can be seen in SpiderMonkey implementation (but only up to version 1.7). Other implementations (including newer versions of SpiderMonkey) do not set a prototype for that special object:

function foo() {
 
  var x = 10;
 
  (function bar() {
 
    alert(x); // 20, but not 10, as don't reach AO(foo) 
 
    // "x" is resolved by the chain:
    // AO(bar) - no -> __specialObject(bar) -> no
    // __specialObject(bar).[[Prototype]] - yes: 20
 
  })();
}
 
Object.prototype.x = 20;
 
foo();
 

Notice, in ES5 this behavior was changed and in current Firefox versions the environment which stores the name of the FE does not inherit from Object.prototype.

ECMAScript implementation from Microsoft — JScript which is currently built into Internet Explorer (up to JScript 5.8 — IE8) has a number of bugs related with named function expressions (NFE). Every of these bugs completely contradicts ECMA-262-3 standard; some of them may cause serious errors.

First, JScript in this case breaks the main rule of FE that they should not be stored in the variable object by name of functions. An optional FE name which should be stored in the special object and be accessible only inside the function itself (and nowhere else) here is stored directly in the parent variable object. Moreover, named FE is treated in JScript as the function declaration (FD), i.e. is created on entering the context stage and is available before the definition in the source code:

// FE is available in the variable object
// via optional name before the
// definition like a FD
testNFE();
 
(function testNFE() {
  alert('testNFE');
});
 
// and also after the definition
// like FD; optional name is
// in the variable object
testNFE();
 

As we see, complete violation of rules.

Secondly, in case of assigning the named FE to a variable at declaration, JScript creates two different function objects. It is difficult to name such behavior as logical (especially considering that outside of NFE its name should not be accessible at all):

var foo = function bar() {
  alert('foo');
};
 
alert(typeof bar); // "function", NFE again in the VO – already mistake
 
// but, further is more interesting
alert(foo === bar); // false!
 
foo.x = 10;
alert(bar.x); // undefined
 
// but both function make 
// the same action
 
foo(); // "foo"
bar(); // "foo"
 

Again we see the full disorder.

However it is necessary to notice that if to describe NFE separately from assigning to variable (for example via the grouping operator), and only after that to assign it to a variable, then check on equality returns true just like it would be one object:

(function bar() {});
 
var foo = bar;
 
alert(foo === bar); // true
 
foo.x = 10;
alert(bar.x); // 10
 

This moment can be explained. Actually, again two objects are created but after that remains, really, only one. If again to consider that NFE here is treated as the function declaration (FD) then on entering the context stage FD bar is created. After that, already at code execution stage the second object — function expression (FE) bar is created and is not saved anywhere. Accordingly, as there is no any reference on FE bar it is removed. Thus there is only one object — FD bar, the reference on which is assigned to foo variable.

Thirdly, regarding the indirect reference to a function via arguments.callee, it references that object with which name a function is activated (to be exact — functions since there are two objects):

var foo = function bar() {
 
  alert([
    arguments.callee === foo,
    arguments.callee === bar
  ]);
 
};
 
foo(); // [true, false]
bar(); // [false, true]
 

Fourthly, as JScript treats NFE as usual FD, it is not submitted to conditional operators rules, i.e. just like a FD, NFE is created on entering the context and the last definition in a code is used:

var foo = function bar() {
  alert(1);
};
 
if (false) {
 
  foo = function bar() {
    alert(2);
  };
 
}
bar(); // 2
foo(); // 1
 

This behavior can also be “logically” explained. On entering the context stage the last met FD with name bar is created, i.e. function with alert(2). After that, at code execution stage already new function — FE bar is created, the reference on which is assigned to foo variable. Thus (as further in the code the if-block with a condition false is unreachable), foo activation produces alert(1). The logic is clear, but taking into account IE bugs, I have quoted “logically” word since such implementation is obviously broken and depends on JScript bugs.

And the fifth NFE bug in JScript is related with creation of properties of global object via assigning value to an unqualified identifier (i.e. without var keyword). Since NFE is treated here as FD and, accordingly, stored in the variable object, assignment to unqualified identifier (i.e. not to variable but to usual property of global object) in case when the function name is the same as unqualified identifier, this property does not become global.

(function () {
 
  // without var not a variable in the local
  // context, but a property of global object
 
  foo = function foo() {};
 
})();
 
// however from the outside of
// anonymous function, name foo
// is not available
 
alert(typeof foo); // undefined
 

Again, the “logic” is clear: the function declaration foo gets to the activation object of a local context of anonymous function on entering the context stage. And at the moment of code execution stage, the name foo already exists in AO, i.e. is treated as local. Accordingly, at assignment operation there is simply an update of already existing in AO property foo, but not creation of new property of global object as should be according to the logic of ECMA-262-3.

This type of function objects is discussed separately from FD and FE since it also has its own features. The main feature is that the [[Scope]] property of such functions contains only global object:

var x = 10;
 
function foo() {
 
  var x = 20;
  var y = 30;
 
  var bar = new Function('alert(x); alert(y);');
 
  bar(); // 10, "y" is not defined
 
}
 

We see that the [[Scope]] of bar function does not contain AO of foo context — the variable “y” is not accessible and the variable “x” is taken from the global context. By the way, pay attention, the Function constructor can be used both with new keyword and without it, in this case these variants are equivalent.

The other feature of such functions is related with Equated Grammar Productions and Joined Objects. This mechanism is provided by the specification as suggestion for the optimization (however, implementations have the right not to use such optimization). For example, if we have an array of 100 elements which is filled in a loop with functions, then implementation can use this mechanism of joined objects. As a result only one function object for all elements of an array can be used:

var a = [];
 
for (var k = 0; k < 100; k++) {
  a[k] = function () {}; // possibly, joined objects are used
}
 

But functions created via Function constructor are never joined:

var a = [];
 
for (var k = 0; k < 100; k++) {
  a[k] = Function(''); // always 100 different funcitons
}
 

Another example related with joined objects:

function foo() {
 
  function bar(z) {
    return z * z;
  }
 
  return bar;
}
 
var x = foo();
var y = foo();
 

Here also implementation has the right to join objects x and y (and to use one object) because functions physically (including their internal [[Scope]] property) are not distinguishable. Therefore, the functions created via Function constructor always require more memory resources.

The pseudo-code of function creation algorithm (except steps with joined objects) is described below. This description helps to understand in more detail which function objects exist in ECMAScript. The algorithm is identical for all function types.

F = new NativeObject();
 
// property [[Class]] is "Function"
F.[[Class]] = "Function"
 
// a prototype of a function object
F.[[Prototype]] = Function.prototype
 
// reference to function itself
// [[Call]] is activated by call expression F()
// and creates a new execution context
F.[[Call]] = <reference to function>
 
// built in general constructor of objects
// [[Construct]] is activated via "new" keyword
// and it is the one who allocates memory for new
// objects; then it calls F.[[Call]]
// to initialize created objects passing as
// "this" value newly created object 
F.[[Construct]] = internalConstructor
 
// scope chain of the current context
// i.e. context which creates function F
F.[[Scope]] = activeContext.Scope
// if this functions is created 
// via new Function(...), then
F.[[Scope]] = globalContext.Scope
 
// number of formal parameters
F.length = countParameters
 
// a prototype of created by F objects
__objectPrototype = new Object();
__objectPrototype.constructor = F // {DontEnum}, is not enumerable in loops
F.prototype = __objectPrototype
 
return F
 

Pay attention, F.[[Prototype]] is a prototype of the function (constructor) and F.prototype is a prototype of objects created by this function (because often there is a mess in terminology, and F.prototype in some articles is named as a “prototype of the constructor” that is incorrect).

This article has turned out rather big; however, we will mention functions again when will discuss their work as constructors in one of chapters about objects and prototypes which follow. As always, I am glad to answer your questions in comments.


Translated by: Dmitry A. Soshnikov.
Published on: 2010-04-05

Originally written by: Dmitry A. Soshnikov [ru, read »]
Originally published on: 2009-07-08

Tags: , , , ,

 
 
 

31 Comments:

  1. Gravatar of joseanpg joseanpg
    10. April 2010 at 16:36

    This is a very good article. Congratulations Dmitry!


  2. Gravatar of Dmitry A. Soshnikov Dmitry A. Soshnikov
    11. April 2010 at 00:52

    @joseanpg

    thanks Jose.


  3. Gravatar of Alejandro Moreno Alejandro Moreno
    13. April 2010 at 21:12

    I *love* this series!

    If you allow me to nit-pick, you left one instance of нет and да:

    AO(bar FD or anonymous FE) ->; нет ->;
    AO(bar FD or anonymous FE).[[Prototype]] ->; да ->; 10
    

    And “their” -> “they are” in the following line:
    “(to be exact — functions since their two objects)”

    Thanks again for this fantastic series.


  4. Gravatar of Dmitry A. Soshnikov Dmitry A. Soshnikov
    13. April 2010 at 21:40

    @Alejandro Moreno

    Thanks Alejandro, fixed. You can send me all wording corrections which you find via mail.

    Dmitry.


  5. Gravatar of jomaras jomaras
    29. April 2010 at 18:04

    Dmitry, great series of articles!

    Just a question – do you have any thoughts on code set as HTML node attribute value.

    e.g.

    if the onclick is a property of a HTML node object, do you have any idea how do they handle this case of setting the property of HTMLNode object to, in this case two statements?

    Do they create a function expression as a wrapper??

    Thanks and keep up the good work!

    Josip


  6. Gravatar of Dmitry A. Soshnikov Dmitry A. Soshnikov
    29. April 2010 at 18:53

    @jomaras

    thanks.

    if the onclick is a property of a HTML node object, do you have any idea how do they handle this case of setting the property of HTMLNode object to, in this case two statements?

    Do they create a function expression as a wrapper??

    Actually, this isn’t a part of ECMAScript and relates already to the implementation of the host environment — in this case to the DOM.

    So, to know how exactly some implementation manages this case, we should examines sources of those implementations.

    But in general, yep, there is nothing else as creating of the corresponding method (based on attributes value, i.e. source code) for the node object.

    For example, in Firefox:

    <input type="text" id="el" onclick="alert(event);" />
    var el = document.getElementById('el');
    
    // function object is build and bound
    // to the el node object
    //
    // function onclick(even) {
    //   alert(event);
    // }
    
    alert(el.onclick);

    So you see, that Gecko engine creates function with the same name “onclick” and even hardcoded by default parameter name — “event” (in IE it is global property). And the body of this function — is the source code taken from the “onclick” attribute. Therefore, we can use name “event” in that attribute value in FF.

    And “onclick” attribute is still string:

    var onClickAttr = el.getAttribute("onclick");
    
    // "string", "alert(event);"
    alert([typeof onClickAttr, onClickAttr]);

    But setting corresponding method doesn’t update in FF “onclick” attribute:

    el.onclick = function (e) {
      alert(e);
    };
    
    // source code of the
    // new funciton
    alert(el.onclick);
    
    // get again attribute value after that
    onClickAttr = el.getAttribute("onclick");
    
    // still old "alert(event);"
    alert(onClickAttr);

    And setting the attribute doesn’t update “onclick” method. Meanwhile on real clicking on the element after that new event set via attribute — we see reaction of this new source code evaluated:

    el.setAttribute("onclick", "alert(1);");
    
    onClickAttr = el.getAttribute("onclick");
    
    // "alert(1);"
    alert(onClickAttr);
    
    // stil old with "alert(e);"
    alert(el.onclick);

    But that just about FF. I.e. it depends on implementation and it depends twice because it is even not implementation of JS but of the host environment.

    In Safari (WebKit) and Chrome (V8) the last alert shows updated via the attribute setting state:

    // function onlick(event) {alert(1);}
    alert(el.onclick);

    IE vice-versa — shows correctly all updates of “onclick” attribute/method, but doesn’t set handler at all if you set it via dynamic attribute setting.

    So, the host environment world has own privileges (and can implement such cases in own manner) and also has own bugs.

    Dmitry.


  7. Gravatar of jomaras jomaras
    30. April 2010 at 10:38

    Thanks for the effort and the in-depth answer, it is very helpful.


  8. Gravatar of Rolan Rolan
    8. September 2010 at 00:59

    In your example of calling FE right after creation, you have

    object.bar = function() { ...

    This should be

    foo.bar = function() { ...

    Thank you for the articles. Very helpful for those (like me) who are too lazy to read the spec.


  9. Gravatar of Dmitry A. Soshnikov Dmitry A. Soshnikov
    9. September 2010 at 10:35

    @Rolan

    Thanks, yeah, it was a typo.

    Dmitry.


  10. Gravatar of nag nag
    12. October 2010 at 06:48

    hi Dmitry,

    Your effort to disseminate JavaScript concepts is incomparable. I did learn a so much.
    In the following context:
    “Also in the definition is said that FE is created at the code execution stage and is not stored in the variable object. Let’s see this behavior on the example:

    // FE is not available neither before the definition  
    // (because it is created at code execution phase),  
    alert(foo); // "foo" is not defined  
    (function foo() {});  
    // nor after, because it is not in the VO  
    alert(foo);  // "foo" is not defined  

    when i execute this script in IE 8 the output is not “undefined” rather the output is the funcion it self. i.e. (function foo(){});. Can you please verify if this is browser/version specific.

    -nag


  11. Gravatar of Dmitry A. Soshnikov Dmitry A. Soshnikov
    12. October 2010 at 11:48

    @nag

    when i execute this script in IE 8 the output is not “undefined” rather the output is the funcion it self. i.e. (function foo(){});. Can you please verify if this is browser/version specific.

    Yes, this is IE’s specific behavior, and it’s not a feature, it’s a bug. An identifier (a name) of a function expression should not pollute outside variable object.

    Read again carefully section NFE and JScript devoted to JScript’s (IE) bugs. They should be fixed (possibly not all) though in IE9.

    Dmitry.


  12. Gravatar of nag nag
    16. October 2010 at 01:42

    Dmitry,

    Under the topic NFE and JScript,

    (function bar() {});  
    var foo = bar;  
    alert(foo === bar); // true  
    foo.x = 10;  
    alert(bar.x); // 10  
    

    I do agree the behaviour of IE.
    But as mentioned the syntax of FD is function name(){}. Hope you do agree with me on this.

    Now in the same example above,

    (function bar() {});   
    alert(bar); 
    

    the output is (function bar(){});, which is not a function declaration syntax as it is being enclosed by parenthesis.

    Thus, can i say it is still referring to an expression as the output is enclosed in parenthesis?

    thanks

    -nag


  13. Gravatar of Dmitry A. Soshnikov Dmitry A. Soshnikov
    16. October 2010 at 19:22

    @nag

    But as mentioned the syntax of FD is function name(){}. Hope you do agree with me on this.

    It mostly not about syntax, but about position in the source code. FEs are always in an expression positions. FDs only at Program level or directly inside another function.

    So, a FE can be without parentheses, but still be a FE:

    1, function foo() {};
    // it's not available (excluding IE's bug)
    alert(typeof foo); // "undefined", but not "function"

    the output is (function bar(){});, which is not a function declaration syntax as it is being enclosed by parenthesis.

    Thus, can i say it is still referring to an expression as the output is enclosed in parenthesis?

    Also an IE’s behavior. IE grabs into the string representation of a function (in alert in this case exactly toString method is called, which is may be an implementation dependent) not only parenthesis, but also comments:

    // only IE, e.g. IE8
    (/* comment */ (((function foo(){}) /* also comment */)));
    alert(foo); // (/* comment */ (((function foo(){}) /* also comment */)))
    

    Dmitry.


  14. Gravatar of nag nag
    18. October 2010 at 22:05

    Dmitry,

    thank you for clarifying…
    -nag


  15. Gravatar of torg torg
    10. March 2011 at 15:53

    This was an astonishing read. Amazing work! Keep it up


  16. Gravatar of MrRoland MrRoland
    2. June 2012 at 07:40

    Dmitry,

    I was perusing the standard and wonder if the construction (FunctionExpression) is actually valid because according to the grammar it is not. Take a look at the following stackoverflow question.


  17. Gravatar of MrRoland MrRoland
    2. June 2012 at 14:14

    My last comment was wrong, actually (FunctionExpression) is valid, take a look at the linked stackoverflow question. Sorry.


  18. Gravatar of Dmitry Soshnikov Dmitry Soshnikov
    2. June 2012 at 17:12

    @MrRoland, yes, correct, FunctionExpression is a part of the MemberExpression there, and therefore is allowed.


  19. Gravatar of AlexOnTheMoon AlexOnTheMoon
    17. December 2012 at 15:29

    Thanks a lot for you explanation on function expressions and why we need the grouping parenthesis !! Your “no non-sense” and precise approach made it very easy for me to understand.

    I’ve been reading countless articles about this feature but none of them were successful at making it really clear like yours do ! Thanks again, keep up the good work !


  20. Gravatar of Steven Guan Steven Guan
    2. January 2013 at 07:46

    Hi Dmitry,
    I tried your example as following in FireFox17.0.1 and Chrome 23.0.1271.97.

    function foo() {
      
      var x = 10;
      
      (function bar() {
      
        alert(x); // 20, but not 10, as don't reach AO(foo)
      
        // "x" is resolved by the chain:
        // AO(bar) - no -> __specialObject(bar) -> no
        // __specialObject(bar).[[Prototype]] - yes: 20
      
      })();
    }
      
    Object.prototype.x = 20;
      
    foo();
    

    I got the output is 10. Not sure if I miss something


  21. Gravatar of Dmitry Soshnikov Dmitry Soshnikov
    2. January 2013 at 22:10

    @Steven Guan

    Yeah, it seems like it was fixed in the latest SpiderMonkey versions, I should mention it in this chapter, thanks. This is correct according to the new spec ES5.


  22. Gravatar of clark clark
    8. January 2013 at 14:22

    Hey Dmitry, could you please clarify this statement from the text: “they [Function Statements] are not real function expressions since they cannot be called without surrounding parentheses.”

    I’m confused as to what is meant here. Is it that if a function is created through a FS, it can’t be immediately invoked without a group operator?

    Thanks.


  23. Gravatar of Steven Guan Steven Guan
    8. January 2013 at 20:51

    Hi Dmitry
    It seems that try different FE will have different prototype

    var mf1 = function ( ele){
        console.log(ele + "");
    }
    console.log('mf1.prototype',mf1.prototype);
    var mf11 = function _mf11 ( ele){
        console.log(ele + "");
    }
    console.log('mf11.prototype',mf11.prototype);
    

    you will get

    f1.prototype        Object {}
    f11.prototype       _f11 {}

    I’m confused. Why such behavior?

    may just due to lack of function name in first FE? looks others are same


  24. Gravatar of Feroz Feroz
    17. March 2013 at 02:06

    Hi Dmitry,

    Thanks for the other “information packed” article.

    meanwhile, I was trying this code to check the accessibility

    (function(){
        var foo = function foo(){};
    });
    console.log(foo); // 'foo' is not defined
    

    but when i try same with “typeof” it gives different output.

    (function(){
        var foo = function foo(){};
    });
    console.log(typeof foo); // undefined
    

    So what i understand from this is when entering on context stage anything follows by ‘typeof’ is initializes with value undefined.

    Please correct me if wrong?


  25. Gravatar of Dmitry Soshnikov Dmitry Soshnikov
    17. March 2013 at 12:31

    @clark

    I’m confused as to what is meant here. Is it that if a function is created through a FS, it can’t be immediately invoked without a group operator?

    Yes, that’s correct. FS should be surrounded by the parens (which automatically converts it to FE) in order to be called.

    @Steven Guan

    you will get

    f1.prototype        Object {}
    f11.prototype       _f11 {}

    I’m confused. Why such behavior?

    may just due to lack of function name in first FE? looks others are same

    Interesting. It seems like it’s only the way Firebug displays the value of the prototype property. If the constructor function has the name, it’s displayed. But semantically there is no (should not be) any difference between these two use-cases.

    @Feroz

    but when i try same with “typeof” it gives different output.

    So what i understand from this is when entering on context stage anything follows by ‘typeof’ is initializes with value undefined.

    That’s a good observation. However, it relates only to the semantics of the typeof operator. We may pass any value (even non-existing yet) to the typeof. This allows using this operator for existence checks:

    console.log(typeof nonExistingVar); // "undefined"

    But if we try to get the real contents of a non-existing variable, it’s already a reference error:

    console.log(nonExistingVar); // ReferenceError

    And this is the main feature of the typeof: it doesn’t try to get the value of the variable, but only checks whether this reference can be resolved (in other words, whether this variable exists).

    The same with non-existing properties, but in contrast with variables, reading a property also returns undefined

    var foo = {};
    console.log(typeof foo.nonExistingProperty); // "undefined"
    console.log(foo.nonExistingProperty); // undefined

    And since we may treat global variables as properties of the global object, we may check like this:

    console.log(window.nonExistingVar); // undefined. Or this.nonExistingVar

    Notice though, that the typeof returns "undefined" also for explicit undefined values:

    var foo = undefined;
    console.log(typeof foo); // "undefined"

    So we cannot say whether foo doesn’t exist or just have the value undefined. So for existence check we can use in operator:

    console.log('nonExistingVar' in window); // false

    P.S.: and in your example with immediately invoked function which creates local foo — there correctly foo should not exist after the function execution, that is correctly reflected in both cases.


  26. Gravatar of Feroz Feroz
    18. March 2013 at 05:02

    Thanks Dmitry,

    I got it… :)


  27. Gravatar of hr hr
    3. August 2013 at 08:28

    Dmitry,
    Thanks for the awesome blog. Had a question about this example:

    var foo = {};
      
    (function initialize() {
      
      var x = 10;
      
      foo.bar = function () {
        alert(x);
      };
      
    })();
      
    foo.bar(); // 10;
      
    alert(x); // "x" is not defined

    The code seems to work.

    Maybe I am missing something-if the FE does not pollute VO and is created only in code exec phase, how does identifier "x" gets resolved by [[scope]] of foo.bar?

    Based on my understanding, the [[scope]] of foo.bar would contain the scope of FE “Initialize” context-since that is not supposed to pollute the VO and only gets created in execution phase, I would think there is no AO of Initializecontext-which is where “X” is, hence [[scope]] of foo.bar will only contain VO of global context.
    In other words:

    foo.bar.[[scope]] = InitialiazeContext.Scope.
    InitializeContext.Scope = AO.concat([[scope]]) = [Globalcontext.VO];

    as the AO is not created for FE.

    Since “X” is not in Globalcontext, how does it get resolved?


  28. Gravatar of Dmitry Soshnikov Dmitry Soshnikov
    4. August 2013 at 19:15

    @hr, activation object (AO) is always created at function execution for any function type. The AO contains function parameters and local variables (i.e. AO of the initialize contains x; hence the foo.bar captures it too in its [[scope]]).

    That a FE doesn’t pollute VO, is meant that it doesn’t pollute outer VO where it’s created. I.e. initialize doesn’t pollute global VO (you can’t call it by name, since it’s not in VO).


  29. Gravatar of hr hr
    4. August 2013 at 21:59

    Phase 1:
    On entering code context stage

    globalContext. VO = { foo: undefined}

    Phase 2:
    On code execution phase, before creating FE “Initialize”
    scope = specialObject + globalContext.VO;
    After creation FE Initialize:

    a)initializeContext.[[scope]] = 
                     specialObject + globalContext.VO
                       = 
              [ {initialize:},{foo:undefined}]

    b) after executing Var x= 10;
    it gets added to scope in the front ?

    initializeContext.Scope = 
       [ {x:10},{initialize:,{foo:{}}]

    c) After executing foo.bar =…. which is an assignment expression , hence an FE, FE gets created at that point foo.bar gets [[scope]] property

    foo.bar.[[scope]] = calling context. scope 
                       = initializeContext.scope
                       = [ {x:10},{initialize:,{foo:{}}]

    d) This gets updated to globalContext. vo since foo is part of globalContext

    globalContext.VO = [{foo.bar :,
                        foo.bar.[[scope]]:
                           [ {x:10},{initialize:,{foo:{}}]
                         ]

    e) when foo.bar() gets called foo.bar.[[scope]] will contain x , which came from initialContext.Scope

    is that how it works?


  30. Gravatar of Dmitry Soshnikov Dmitry Soshnikov
    4. August 2013 at 22:13

    @hr, yes, that’s correct.


  31. Gravatar of hr hr
    5. August 2013 at 06:45

    btw, Thanks Dmitry for the response.


Leave a Reply

Code: For code you can use tags [js], [text], [ruby] and other.

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>