in ECMAScript

ECMA-262-3 in detail. Chapter 4. Scope chain.

Read this article in: Russian, French.

Introduction

As we already know from the second chapter concerning the variable object, the data of an execution context (variables, function declarations, and formal parameters of functions) are stored as properties of the variables object.

Also, we know that the variable object is created and filled with initial values every time on entering the context, and that its updating occurs at code execution phase.

This chapter is devoted one more detail directly related with execution contexts; this time, we will mention a topic of a scope chain.

Definition

If to describe briefly and showing the main point, a scope chain is mostly related with inner functions.

As we know, ECMAScript allows creation of inner functions and we can even return these functions from parent functions.

var x = 10;

function foo() {
  
  var y = 20;
  
  function bar() {
    alert(x + y);
  }
  
  return bar;

}

foo()(); // 30

Thus, is known that every context has its own variables object: for the global context it is global object itself, for functions it is the activation object.

And the scope chain is exactly this list of all (parent) variable objects for the inner contexts. This chain is used for variables lookup. I.e. in the example above, scope chain of “bar” context includes AO(bar), AO(foo) and VO(global).

But, let’s examine this topic in detail.

Let’s begin with the definition and further will discuss deeper on examples.

Scope chain is related with an execution context a chain of variable objects which is used for variables lookup at identifier resolution.

The scope chain of a function context is created at function call and consists of the activation object and the internal [[Scope]] property of this function. We will discuss the [[Scope]] property of a function in detail below.

Schematically in the context:

activeExecutionContext = {
    VO: {...}, // or AO
    this: thisValue,
    Scope: [ // Scope chain
      // list of all variable objects
      // for identifiers lookup
    ] 
};
 

where Scope by definition is:

Scope = AO + [[Scope]]

For our examples we can represent Scope, and [[Scope]] as normal ECMAScript arrays:

var Scope = [VO1, VO2, ..., VOn]; // scope chain

The alternative structure view can be represented as a hierarchical object chain with the reference to the parent scope (to the parent variable object) on every link of the chain. For this view corresponds __parent__ concept of some implementations which we discussed in the second chapter devoted variable object:

var VO1 = {__parent__: null, ... other data}; -->
var VO2 = {__parent__: VO1, ... other data}; -->
// etc.

But to represent a scope chain using an array is more convenient, so we will use this approach. Besides, the specification statements abstractly itself (see 10.1.4) that “a scope chain is a list of objects”, regardless that on the implementation level can be used the approach with the hierarchical chain involving the __parent__ feature. And the array abstract representation is a good candidate for the list concept.

The combination AO + [[Scope]] and also process of identifier resolution, which we will discuss below, are related with the life cycle of functions.

Function life cycle

Function life cycle is divided into a stage of creation and a stage of activation (call). Let’s consider them in detail.

Function creation

As is known, function declarations are put into variable/activation object (VO/AO) on entering the context stage. Let’s see on the example a variable and a function declaration in the global context (where variable object is the global object itself, we remember, yes?):

var x = 10;
 
function foo() {
  var y = 20;
  alert(x + y);
}
 
foo(); // 30
 

At function activation, we see correct (and expected) result – 30. However, there is one very important feature.

Before this moment we spoke only about variable object of the current context. Here we see that “y” variable is defined in function “foo” (which means it is in the AO of “foo” context), but variable “x” is not defined in context of “foo” and accordingly is not added into the AO of “foo”. At first glance “x” variable does not exist at all for function “foo”; but as we will see below — only “at first glance”. We see that the activation object of “foo” context contains only one property — property “y”:

fooContext.AO = {
  y: undefined // undefined – on entering the context, 20 – at activation
};
 

How does function “foo” have access to “x” variable? It is logical to assume that function should have access to the variable object of a higher context. In effect, it is exactly so and, physically this mechanism is implemented via the internal [[Scope]] property of a function.

[[Scope]] is a hierarchical chain of all parent variable objects, which are above the current function context; the chain is saved to the function at its creation.

Notice the important point — [[Scope]] is saved at function creation — statically (invariably), once and forever — until function destruction. I.e. function can be never called, but [[Scope]] property is already written and stored in function object.

Another moment which should be considered is that [[Scope]] in contrast with Scope (Scope chain) is the property of a function instead of a context. Considering the above example, [[Scope]] of the “foo” function is the following:

foo.[[Scope]] = [
  globalContext.VO // === Global
];
 

And further, by a function call as we know, there is an entering a function context where the activation object is created and this value and Scope (Scope chain) are determined. Let us consider this moment in detail.

Function activation

As it has been said in definition, on entering the context and after creation of AO/VO, Scope property of the context (which is a scope chain for variables lookup) is defined as follows:

Scope = AO|VO + [[Scope]]

High light here is that the activation object is the first element of the Scope array, i.e. added to the front of scope chain:

Scope = [AO].concat([[Scope]]);

This feature is very important for the process of identifier resolution.

Identifier resolution is a process of determination to which variable object in scope chain the variable (or the function declaration) belongs.

On return from this algorithm we have always a value of type Reference, which base component is the corresponding variable object (or null if variable is not found), and a property name component is the name of the looked up (resolved) identifier. In detail Reference type is discussed in the Chapter 3. This.

Process of identifier resolution includes lookup of the property corresponding to the name of the variable, i.e. there is a consecutive examination of variable objects in the scope chain, starting from the deepest context and up to the top of the scope chain.

Thus, local variables of a context at lookup have higher priority than variables from parent contexts, and in case of two variables with the same name but from different contexts, the first is found the variable of deeper context.

Let’s a little complicate an example described above and add additional inner level:

var x = 10;
 
function foo() {
 
  var y = 20;
 
  function bar() {
    var z = 30;
    alert(x +  y + z);
  }
 
  bar();
}
 
foo(); // 60
 

For which we have the following variable/activation objects, [[Scope]] properties of functions and scope chains of contexts:

Variable object of the global context is:

globalContext.VO === Global = {
  x: 10
  foo: <reference to function>
};
 

At foo creation, the [[Scope]] property of foo is:

foo.[[Scope]] = [
  globalContext.VO
];
 

At foo function call, the activation object of foo context is:

fooContext.AO = {
  y: 20,
  bar: <reference to function>
};
 

And the scope chain of foo context is:

fooContext.Scope = fooContext.AO + foo.[[Scope]] // i.e.:

fooContext.Scope = [
  fooContext.AO,
  globalContext.VO
];
 

At creation of inner bar function its [[Scope]] is:

bar.[[Scope]] = [
  fooContext.AO,
  globalContext.VO
];
 

At bar function call, the activation object of bar context is:

barContext.AO = {
  z: 30
};

And the scope chain of bar context is:

barContext.Scope = barContext.AO + bar.[[Scope]] // i.e.:

barContext.Scope = [
  barContext.AO,
  fooContext.AO,
  globalContext.VO
];
 

Identifier resolution for x, y and z names:

- "x"
-- barContext.AO // not found
-- fooContext.AO // not found
-- globalContext.VO // found - 10
 
- "y"
-- barContext.AO // not found
-- fooContext.AO // found - 20
 
- "z"
-- barContext.AO // found - 30

Scope features

Let’s consider some important features related with Scope chain and [[Scope]] property of functions.

Closures

Closures in ECMAScript are directly related with the [[Scope]] property of functions. As it has been noted, [[Scope]] is saved at function creation and exists until the function object is destroyed. Actually, a closure is exactly a combination of a function code and its [[Scope]] property. Thus, [[Scope]] contains that lexical environment (the parent variable object) in which function is created. Variables from higher contexts at the further function activation will be searched in this lexical (statically saved at creation) chain of variable objects.

Examples:

var x = 10;

function foo() {
  alert(x);
}

(function () {
  var x = 20;
  foo(); // 10, but not 20
})();

We see that x variable is found in the [[Scope]] of foo function, i.e. for variables lookup the lexical (closured) chain defined at the moment of function creation, but not the dynamic chain of the call (at which value of x variable would be resolved to 20) is used.

Another (classical) example of closure:

function foo() {

  var x = 10;
  var y = 20;

  return function () {
    alert([x, y]);
  };

}

var x = 30;

var bar = foo(); // anonymous function is returned

bar(); // [10, 20]

Again we see that for the identifier resolution the lexical scope chain defined at function creation is used — the variable x is resolved to 10, but not to 30. Moreover, this example clearly shows that [[Scope]] of a function (in this case of the anonymous function returned from function foo) continues to exist even after the context in which a function is created is already finished.

In more details about the theory of closures and their implementation in ECMAScript read in the Chapter 6. Closures.

[[Scope]] of functions created via Function constructor

In the examples above we see that function at creation gets the [[Scope]] property and via this property it accesses variables of all parent contexts. However, in this rule there is one important exception, and it concerns functions created via the Function constructor.

var x = 10;
 
function foo() {
 
  var y = 20;
 
  function barFD() { // FunctionDeclaration
    alert(x);
    alert(y);
  }
 
  var barFE = function () { // FunctionExpression
    alert(x);
    alert(y);
  };
 
  var barFn = Function('alert(x); alert(y);');
 
  barFD(); // 10, 20
  barFE(); // 10, 20
  barFn(); // 10, "y" is not defined
 
}
 
foo();
 

As we see, for barFn function which is created via the Function constructor the variable y is not accessible. But it does not mean that function barFn has no internal [[Scope]] property (else it would not have access to the variable x). And the matter is that [[Scope]] property of functions created via the Function constructor contains always only the global object. Consider it since, for example, to create closure of upper contexts, except global, via such function is not possible.

Two-dimensional Scope chain lookup

Also, an important point at lookup in scope chain is that prototypes (if they are) of variable objects can be also considered — because of prototypical nature of ECMAScript: if property is not found directly in the object, its lookup proceeds in the prototype chain. I.e. some kind of 2D-lookup of the chain: (1) on scope chain links, (2) and on every of scope chain link — deep into on prototype chain links. We can observe this effect if define property in Object.prototype:

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

Activation objects do not have prototypes what we can see in the following example:

function foo() {
 
  var x = 20;
 
  function bar() {
    alert(x);
  }
 
  bar();
}
 
Object.prototype.x = 10;
 
foo(); // 20
 

If activation object of bar function context would have a prototype, then property x should be resolved in Object.prototype because it is not resolved directly in AO. But in the first example above, traversing the scope chain in identifier resolution, we reach the global object which (in some implementation but not in all) is inherited from Object.prototype and, accordingly, x is resolved to 10.

The similar situation can be observed in some versions of SpiderMokey with named function expressions (abbreviated form is NFE), where special object which stores the optional name of function-expression is inherited from Object.prototype, and also in some versions of Blackberry implementation where activation objects are inherited from Object.prototype. But more detailed this features are discussed in Chapter 5. Functions.

Scope chain of the global and eval contexts

Here is not so much interesting, but it is necessary to note. The scope chain of the global context contains only global object. The context with code type “eval” has the same scope chain as a calling context.

globalContext.Scope = [
  Global
];
 
evalContext.Scope === callingContext.Scope;
 

Affecting on Scope chain during code execution

In ECMAScript there are two statements which can modify scope chain at runtime code execution phase. These are with statement and catch clause. Both of them add to the front of scope chain the object required for lookup identifiers appearing within these statements. I.e., if one of these case takes place, scope chain is schematically modified as follows:

Scope = withObject|catchObject + AO|VO + [[Scope]]

The statement with in this case adds the object which is its parameter (and thus properties of this object become accessible without prefix):

var foo = {x: 10, y: 20};
 
with (foo) {
  alert(x); // 10
  alert(y); // 20
}
 

Scope chain modification:

Scope = foo + AO|VO + [[Scope]]

Let us show once again that the identifier is resolved in the object added by the with statement to the front of scope chain:

var x = 10, y = 10;
 
with ({x: 20}) {
 
  var x = 30, y = 30;
 
  alert(x); // 30
  alert(y); // 30
}
 
alert(x); // 10
alert(y); // 30
 

What happened here? On entering the context phase, “x” and “y” identifiers have been added into the variable object. Further, already at runtime code executions stage, following modifications have been made:

  • x = 10, y = 10;
  • the object {x: 20} is added to the front of scope chain;
  • the met var statement inside with, of course, created nothing, because all variables have been parsed and added on entering the context stage;
  • there is only modification of “x” value, and exactly that “x” which is resolved now in the object added to the front of scope chain at second step; value of this “x” was 20, and became 30;
  • also there is modification of “y” which is resolved in variable object above; accordingly, was 10, became 30;
  • further, after with statement is finished, its special objects is removed from the scope chain (and the changed value “x” – 30 is removed also with that object), i.e. scope chain structure is restored to the previous state which was before with statement augmentation;
  • as we see in last two alerts: the value of “x” in current variable object remains the same and the value of “y” is equal now to 30 and has been changed at with statement work.

Also, a catch clause in order to have access to the parameter-exception creates an intermediate scope object with the only property — exception parameter name, and places this object in front of the scope chain. Schematically it looks so:

try {
  ...
} catch (ex) {
  alert(ex);
}
 

Scope chain modification:

var catchObject = {
  ex: <exception object>
};
 
Scope = catchObject + AO|VO + [[Scope]]

After the work of catch clause is finished, scope chain is also restored to the previous state.

Conclusion

At this stage, we have considerate almost all general concepts concerning execution contexts and related with them details. Further, according to plan, — detailed analysis of function objects: types of functions (FunctionDeclaration, FunctionExpression) and closures. By the way, closures are directly related with the [[Scope]] property discussed in this article, but about it is in appropriate chapter. I will be glad to answer your questions in comments.

Additional literature


Translated by: Dmitry A. Soshnikov.
Published on: 2010-03-21

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

Write a Comment

Comment

70 Comments

  1. [”x” is resolved to 20, but not to 30. ]
    I think your meas is [“ x” is resolved to 10, but not to 30. ]

  2. For examples we represent Scope, and [[Scope]] as normal ECMAScript arrays.

    you means is :
    we can represent Scope, and [[Scope]] as normal ECMAScript arrays.

    right?

    I don’t know how to understand the “for examples”.
    Always felt like something wildly shortcomings.

  3. @justin

    you means is :
    we can represent Scope, and [[Scope]] as normal ECMAScript arrays.

    Yes. I have rewritten this description and added alternative representation of the scope chain (with involving the __parent__ concept). I also moved this paragraph a bit higher (earlier) in the article.

    Dmitry.

  4. thanks!

    another question:

    starting from the deepest context and up to the top bypassing the scope chain.

    I don’t know how to understand the “bypassing the scope chain.”.

    I think you means is :”starting from the deepest context and up to the top the scope chain.“,no “bypass”.

    right?

  5. @justin

    I don’t know how to understand the “bypassing the scope chain.”.

    Yes, a confusing word; I simply removed it.

    Dmitry.

  6. exists until the function exists

    may be you means is “exists until the function exits

    [[Scope]] contains as one of its objects that lexical environment (parent variable object) in which function is created.

    It was too bad to understand, could you explain to me?

  7. @justin

    may be you means is “exists until the function exits

    Yep, it was a typo. Now it is: “exists until the function object is destroyed”. Which means, that a function’s [[Scope]] (list of parent VOs) will be removed when the function itself will be removed.

    [[Scope]] contains as one of its objects that lexical environment (parent variable object) in which function is created.

    It was too bad to understand, could you explain to me?

    I removed the part with “as one of its objects”. Now it should be clearer. If you carefully read about [[Scope]], you should know that this internal function’s property stores a VO of the context in which a function is created.

    Having this code:

    var foo;
    function bar() {}

    the [[Scope]] of the “bar” function is:

    bar.[[Scope]] = { // [[Scope]] is a global object
      foo: undefined,
      bar: <reference to function>,
      __parent__: null
    };

    E.g. for inner function “baz” the [[Scope]] is the following:

    var x = 10;
    function foo() {
      var bar;
      function baz() {}
    }
    

    And we have:

    baz.[[Scope]] = {
      bar: undefined
      __parent__: foo.[[Scope]] // global
    };

    Alternative and more convenient representation of the [[Scope]] isn’t as separate objects with __parent__, but as an array. And we use this approach during this chapter. So the [[Scope]] — is a list which contains all parent variable objects (see 10.1.4).

    For our “baz” function its internal [[Scope]] array is:

    baz.[[Scope]] = [
    
      // foo's VO i.e. AO of foo's context
      {
        bar: undefined,
        baz: <reference to function>
      },
    
      // global VO
      {
        x: 10
      }
    
    ];

    So you see that “baz.[[Scope]]” “contains that (parent) variable object in which function “baz” is created, i.e. the AO of foo’s context.

    And then, when the “baz” will be activated, the scope chain of the baz’s context (a real scope chain which is used for identifier resolution lookup) is:

    Scope(baz) = AO(baz) + baz.[[Scope]];

    I.e. Scope(baz) is being created every time at baz’s activation and is related with the execution context. And the baz.[[Scope]] is created only once — at baz’s creation and related with the baz function.

    Dmitry.

  8. @Dmitry
    Thank you very much !
    more clearly now, I had also get confused by “as one of its objects”.

    other:

    bypassing the scope chain in identifier resolution

    maybe your mean is “traversing the scope chain …”

  9. the sentence “a catch clause that the parameter-exception becomes accessible to it creates new object with the only one property — exception parameter name ” is difficult for me to understand. is [that the parameter-exception becomes accessible to it] a attributive clause
    to qualify [a catch clause]???? forgive my poor english.
    I have another question:do the prototype property store in vo??

  10. I mean the implicit __proto__ property you mentioned in the article javascript: the core

  11. @ju350213

    Thanks, I’ve rewritten a bit this sentence; hope now it sounds easier.

    I have another question:do the prototype property store in vo??
    I mean the implicit __proto__ property you mentioned in the article javascript: the core

    It’s better to put questions related to other articles in their comments. But, on the question — no, implicit [[Prototype]] property (which is __proto__ on figures) is the property of objects.

    However, in some implementations, e.g. SpiderMonkey (Firefox), the global object (which is VO of the global context) inherits from Object.prototype. And in this case your sentence makes sense, since the global object is the VO there and has __proto__.

    P.S.: I also fixed typos in lexical environment article, thanks.

    Dmitry.

  12. Thanks.I know what you said,but what i want to know is where the implicit [[Prototype]] property of objects is stored.in my opinion,all program execution information are stored in execution context stack,so i can’t associate the two things(scope chain and prototype chain).is memory block which is used to store execution context stack information separated from memory block used to store object’s propertys?? In short, i want to know the relationship between the two things(scope chain and prototype chain) in detail.Can you explain it deeply? thanks!

  13. @dmitry
    hi, about this:
    At “foo” activation (on entering the context), the activation object of “foo” context is:

    fooContext.AO = {
      y: 20,
      bar: 
    };
    

    Why at foo activation is on entering the context, not the code execution ?

  14. I think you have an expression error.

    some kind of 2D-lookup of the chain: (1) on scope chain links, (2) and on every of scope chain link — deep into on prototype chain links

    As you say:

    Activation objects do not have prototypes

    Therefore lookup would not deep into prototype chain on every activation object, but only deep into the prototype chain of VO(globalContext) which itself is global object inherited from Object.prototype

  15. ok this is some code

    function myFunc(){
       var myvar = 8;
           function myFunc2(num){
               alert(myvar+num);
           }
    
       myFunc2(2);
    
    }
    
    myFunc();

    i want to clear my mind so pls correct me if am wrong

    i have read allot of articles in stack overflow already but i want to know i understand it well or should i read more.

    to my understanding what happens behind the scene is thatin global execution context there it creates function object with the namemyFunc` and its [[scope]] property assigned to global variable object.

    and when i call myFunc it creates its own execution context and activation object where all of the function’s arguments and function declaration is initialized before any line by line code execution.

    when inner function object is created it’s internal [[scope]] property is assigned the value of its outer execution context’s variable object + global variable object so every function creates its own execution context but before that every function’s internal [[scope]] property is assigned first.

    i have read allot of articles in stack overflow already but i want to know i understand it well or should i read more.

  16. @raziq, yes, this is correct understanding. The [[Scope]] is set at function creation. And when the function is executed, a new execution context (with the activation object that stores local data) is spawned.

  17. Спасибо за статьи, они классные! А теперь комментарий. По сути AO и VO одинаковы, но вы их различаете в статьях так же как и стандарт наверное, и правильно обосновываете это различие, а именно тем, что в случае с вызовом функции, при формировании VO к нему добавляются ” object and are added”, но это не единственное различие, и поэтому вы акцентируете внимание на то, что доступ к глобальному VO может происходить и через window, а к AO доступа нет, т.е. мы не можем создавать переменные в AO без использования var, в случае с VO глобального объекта мы можем window[‘name’] = …, но потом вы указали, что в некоторых реализаций через внутреннее свойство __parent, мы можем получить доступ к AO. Для того чтобы мне запомнить правила мне необходимо понять почему они такие, и вот мне не хватило двух этих различий между AO и VO чтобы их различать, они не были для меня существенные, но потом я представил такую картину, если бы мы имели официальный доступ к AO, тогда я бы мог создавать переменные в функции динамически, на лету, и это можно сделать сейчас через eval(“var …”) , но тогда как бы при этом работал механизм static scope, можно ли его назвать таким в ECMA-262-3, который имеет место быть только в процессе семантического анализа текста программы, то есть на стадиях предкомпиляции. Поэтому наверное eval(“var …”) запрещают в следующих стандартах в strict mode, чтобы была возможность оптимизации closure, например в процессе семантического анализа функции видно, что в функции фигурируют некоторые свободные переменные которые замыкаются на другие, которые в свою очередь известно где объявляются, тогда возможно заранее подготовить структуры данных для быстрого доступа к ним, а не содержать и просматривать всю цепочку вверх для их обнаружения уже в процессе вызова функции.
    Вот пример простой функции

    function f(t) {
       t && eval(t); 
       return a;
    }

    Здесь идентификатор “а” в зависимости от t и контекста исполнения может возвращать разные значения как в dynamic scope.

    var a = 0;
    f(); // =>; 0
    f('var a = 1');// =>; 1
    
    function Z() 
    {
     var a = 2;
     f(); //=>; 2
    }

    И вы тоже потом об этом пишите.
    Вот еще цитата из следующих ваших статей
    “The word “static” relates to ability to determine the scope of an identifier during the parsing stage of a program.”
    В данном случае такой возможности нет у парсера. Почему у меня возникли такие вопросы, мне просто интересно насколько вызов функции производителен, если при каждом вызове просматривать цепочку вверх, предполагая, что там где-то будет находиться переменная, то какой же это вызов будет мощный, плюс с каждой функцией содержать копию цепочки, в верху которой, например, сидит необходимое значение.
    Вот еще пример:

    var x = 10;
    function f(t) {
       t && eval(t); 
       if (--x !== 0)
          f();
       else
          f.F = function () {return a};
    }
    f('var a = 0');
    f.F() // =>; ReferenceError: a is not defined
    
    var x = 10;
    function f(t) {
       var a = 1;
       if (--x !== 0)
          f();
       else
          f.F = function () {return a};
    }
    
    f.F() // =>; Ok, 1
    
    function f(t) {
       t && eval(t); 
       return function() { return a;}
    }
    f('var a = 1')() //=>; Ок, 1

    В первом случае не увидел ‘a’, наверное подумал слишком глубоко, во втором увидел ‘var a’ явно стоит, и подумал ок тут ты сам этого хочешь, получи, а в последнем случае сhrome подумал, но тут не очень глубоко, можно поплавать. Почему во втором так, мне ясно, а вот первый и последний оставляет вопросы, ведь в обоих случаях, когда создается [[Scope]] для функций там по цепочке вверх можно добраться до ‘a’, а в первом случае этого не происходит?

  18. @Oleg,

    VO и AO, по сути, мало чем отличаются (только идеологически), фактически, оба они — лишь хранилища переменных контекста. Только AO – в случае контекстов функций, и предварительно наполняется параметрами функции и объектом arguments. Во всем остальном — это тот же VO.

    Вы правильно заметили, что нельзя создать свойство AO напрямую, но eval, да, это сделать может.

    В строгом режиме eval запускается в отдельной песочнице (создается временное хранилище переменных).

    function f(t) {
       t && eval(t); 
       return a;
    }

    Здесь идентификатор “а” в зависимости от t и контекста исполнения может возвращать разные значения как в dynamic scope.

    var a = 0;
    f(); // =>; 0
    f('var a = 1');// =>; 1
    
    function Z() 
    {
     var a = 2;
     f(); //=>; 2
    }

    Последний пример с функций Z неверный (поэтому, все-таки, это не классический динамический scope). Функция f создана в глобальном контексте, и поэтому может видеть лишь свой AO, либо глобальный контекст (информация о том, какие scope может видеть функция записана при ее создании и определена лексически), но никак не контекст Z, из которого она запускается (как было бы при классическом динамическом scope). Значением последнего запуска будет 0 — из глобального контекста, т.к. код t не передан и a не создается в локальном AO функции f.

    В первом случае не увидел ‘a’, наверное подумал слишком глубоко

    Переменная a не создается в AO f при рекурсивных вызовах (т.к. Вы не передаете код в этом случае — f();. Соответственно, значение f.F = создержит функцию, которая создана при последней рекурсивной итерации, где переменной a нет. Передайте код при рекурсивных вызовах — f(t), и все заработает: глубина тут не влияет.

    Во втором случае var a = 1; всегда явно определяется в AO f и не зависит от кода t.

    В третьем случае — переданный код t нормально исполняется, и поэтому создается a, которая становится так же видна.

  19. Hi Dmitry,

    In your demo below, the final identifier resolution for ‘x’, ‘y’, ‘z’, is based on Scope property of functionConext right?

    That is AO + [[Scope]]. While for example in Closure section, it turns [[Scope]] of function to resolve variable?

    ————————————————————
    Let’s a little complicate an example described above and add additional inner level:

    	var x = 10;
    	  
    	function foo() {
    	  
    	  var y = 20;
    	  
    	  function bar() {
    	    var z = 30;
    	    alert(x +  y + z);
    	  }
    	  
    	  bar();
    	}
    	  
    	foo(); // 60
    ...
    ...
    ...

    Identifier resolution for “x”, “y” and “z” names:

    	- "x"
    	-- barContext.AO // not found
    	-- fooContext.AO // not found
    	-- globalContext.VO // found - 10
    	- "y"
    	-- barContext.AO // not found
    	-- fooContext.AO // found - 20
    	- "z"
    	-- barContext.AO // found - 30

    ———————————————————–

    In Closure section, in following example, you said “x” variable is found in the [[Scope]] of “foo” function. I am so confused. Please help me.

    ———————————————————–
    Examples:

    	var x = 10;
    	 
    	function foo() {
    	  alert(x);
    	}
    	 
    	(function () {
    	  var x = 20;
    	  foo(); // 10, but not 20
    	})();

    We see that “x” variable is found in the [[Scope]] of “foo” function, i.e. for variables lookup the lexical (closured) chain defined at the moment of function creation, but not the dynamic chain of the call (at which value of “x” variable would be resolved to 20) is used.
    ———————————————————–

    Please help, waiting for your reply.

    Regards.

  20. @Hong it’s always AO + [[Scope]] lookup. The [[Scope]] of foo is [{x: 10}], the AO of foo is empty — {} (except implicit arguments object, etc). So, x is found in the [[Scope]].

  21. @Dmitry, after reading this article the second time, I got it. Thanks for your help.

  22. Regarding ‘Two-dimensional Scope chain lookup’:
    – When do variable objects have prototypes? (other than when we are in the global context which is the variable object itself then, and therefore has a prototype of Object.prototype as you said above)
    – Is this loosely defined in the ECMA standard and specific to how it is implemented in the javascript engine?

  23. @Dan, activation/variable objects do not have prototypes by the spec. There are (were) some implementations that implemented activation objects as simple objects with prototypes, but not at the moment.

    An case for `with`-augmented scope chain is a good example of dimensional scope lookup.

    And yes, this is how spec defines it.

  24. Dmitry, first of all, these are the best articles on the world, period, thanks for sharing with us such a technical article which i learned the true power of Javascript.

    Jut a little question, there is a function call and after that, there is (entering the context – Function Activation) and Code Execution.

    So, in your example –

    fooContext.AO = {
      y: 20,
      bar: 
    };
    

    At foo activation, activation object is:

    fooContext.AO = {
      y: undefined,
      bar: 
    };
    

    and the Scope property in the activeExecutionContext Object is created.

    And its updates occurs in Code Execution phase, right?

  25. @Pedro Sousa, thanks, glad that it’s useful, and glad to see more people interested in deep JS.

    Your understanding about the entering and execution phases of the context is absolutely correct, however at that example with y: 20 (which of course may happen only at execution phase), I didn’t want to pay much attention on exact phase (there we’re interested only in what bar function will see — and it will see y as 20), so I replaced the “activation” word with the “call” word to avoid confusions. Thanks for noticing this!

  26. After reading the new environments on 5.1, there is something i didn’t understand.

    // When are [[scope]] used and when is outer?

    var x = 10, y = 30; // adding y from your eexample
    
                function foo() {
                    alert(x);
                }
    
                (function () {
                    var x = 20;
                    foo(); // 10, but not 20 // HERE is found on foo.__scope__
                    console.log(y); // here use outer property of current lexical env or the __scope__ of the anonymous function?
                })();
    

    Environments ( After code execution ) – with/eval excluded, only lexical

     var globalEnv = {
                    lexical: {
                        x: 10,
                        y: 30,
                        foo: 'reference to foo'
                    },
                    outer: null
                };
                
                // AT FOO CREATION
                
                foo.__scope__ = [globalEnv.lexical];
                
                // FOO CALL, FOO ENVIRONMENT
                
                 var fooEnv = {
                    lexical: {
                        
                    },
                    outer: globalEnv.lexical
                };
                
                // ANONYMOUSS FUNCTION CREATION
                
                // anonFunc.__scope__ = globalEnv.lexical
                
                // ANONYMOUS FUNCTION CALL, anon ENVIRONMENT IS:
                
                var anonEnv = {
                    lexical: {
                        x: 20
                    },
                    outer: globalEnv.lexical
                };
    

    // identifier resolution “y”

    anonEnv.lexical — not found
    anonEnv.lexical.outer — found, y = 30

    // WHY NOT SEARCH IN [[SCOPE]] PROPERTY OF THE ANONYMOUS FUNCTION OBJECT for y if aFunction.__scope__ === aFunctionEnv.outer ?

    // Scope chain is related with an execution context a chain of variable objects which is used for variables lookup at identifier resolution.

    i.e, For variables at identifier resolution use outer, for function call’s like the example above search ONLY on __scope__, right?

  27. @Pedro Sousa,

    You correctly described the environment structures of functions. First, the model of a chained (linked) list for environments presented the same as previously, I just used different notation in this chapter. Here I used an array:

    var Scope = [VO1, VO2, ..., VOn]; // scope chain
    

    However, I also mentioned, that we can present it differently:

    var VO1 = {__parent__: null, ... other data}; -->
    var VO2 = {__parent__: VO1, ... other data}; -->
    

    Exactly this second representation is better to use when describing ES5 environments.

    var GlobalEnv = {outer: null, ... other data};
    var SomeFuncEnv = {outer: GlobalEnv, ... func params and local vars};
    

    Notice, that SomeFuncEnv contains all local vars and params (i.e. if we mimic it to ES3 — it would be the Activation Object).

    Every time a function is called, a new environment is created (the same as new fresh AO is created in ES3), and this new environment has as its outer environment the value of SomeFunc.[[Scope]]. Now that SomeFunc.[[Scope]] is also just some environment object with its own outer link.

    Identifier resolution always happens in the environment following the outer link (further and further), if a variable is not found in own environment.

    So in you example, the global environment is:

    var GlobalEnv = {record: {x: 10, y: 20, foo: <func>}, outer: null};
    

    The foo function’s [[Scope]] is (notice, it's not an array in this representation! just the reference to the environment where foo is created, i.e. to the global env):

    foo.[[Scope]] = GlobalEnv;
    

    Now, when the foo is executed (no matter from which place) a fresh environment is created:

    var FooEnv = {record: {}, outer: foo.[[Scope]]};
    

    And identifier resolution happens in the FooEnv:

    x -> found in FooEnv.record? - no
    x -> found in FooEnv.outer.record? - yes, 10
    

    The environment and [[Scope]] of the anonymous function is similar, and will find the y in global env (since no in own record), but it will find x in the own environment record, since it shadowed the global x.

  28. So good Dmitry, thanks for your time, all doubts gone, because i was thinking outer and [[scope]] was diferent things, all makes sense know.

    Now i fully understand the concept of closures and free variables:

    var x = 10;
                
    function foo() {
      var x = 20;
    // this is 'anonFn'
      return function() {
        return x; // it's a free variable
      };
    }
    
    globalEnv = { record: { x: 10,  foo: foo }, outer: null };
    
    foo.__scope__ = [globalEnv];
    fooClosure = { call: anonFn, lexicalEnvironment: anonFn.__scope};
    fooEnv = { record: { x: 20 }, outer: foo.__scope__ };
    var anonFn = {};
    anonFn.__scope__ = [fooEnv];
    anonEnv = { record: {}, outer: anonFn.__scope__ };
    
    

    Thanks Dmitry for your time =)

  29. @Pedro Sousa, yes, now everything is correct 🙂

    One nit: the [[Scope]] (__scope__ in your example)

    // not an "array"
    foo.__scope__ = [globalEnv];
    
    // but just a reference
    foo.__scope__ = globalEnv;
    
  30. var VO1 = {__parent__: null, ... other data}; -->;
    var VO2 = {__parent__: VO1, ... other data}; -->;

    is it correct to say that “__parent__” is a reference to VO where the function was created (i.e the [[scope]] propierty of the function)?

  31. function d() {
       var a=5; // local
       function e() {
          a=4; // global
          return (function(){alert(a);}); 
       }
       return e;
    }
    
    d()()();  //4
    alert(a); //nothing

    why return 4? when a is declared without var, then it should be a global variable belong to global context and it should not be in the AO of the context e. then following the scope chain will find 5 in the AO of d. And the last alert will show 4. However the result is not so.

  32. is it correct to say that “__parent__” is a reference to VO

    Yes, it is correct, although, I’d use ES5 terminology, where that __parent__ is called outer link (meaning the link to the outer environment).

    why return 4? when a is declared without var, then it should be a global variable belong to global context

    Not exactly, when it’s without the var it searches the variable in the nearest outer environment (in the scope chain). In this case it finds the variable a in the environment (in the AO) of the d function.

    It’s only if d wouldn’t have the var a, then it would be global.

  33. When we are talking about scope in javascript, more precisely we are talking about scope chain?. So terms “scope”, and “scope chain” are interchangeable(synonymous)?

  34. @Mark sometimes yes, although more often by “scope” usually current environment (current variable object) is meant.

  35. Hi Dmitry, again me. I am not sure am I correctly understanding stuff so far. I read first 4 articles of ECMA-262-3 series.

    Example:

      var x = 10;
    
      function foo() {
        var y = 20;
        alert(x+y);
      }
    

    in the above example function foo even not called, is able to know about x variable from global context and all that information are stored in the internal [[Scope]] property of foo function object,that is how I understand, is that true ?
    And when I call foo function
    new execution context will be created and we are entering foo context where new AO will be created and filled with y property and also this and arguments will be there. And after that we x & y will be searched in scope chain
    and 30 will be alerted in the end? Is it that correct order, roughly ? Thanks

  36. @blajs, yes, everything is correct actually, except that this is not in the AO, but in the execution context (i.e. when we refer to this, there is no scope chain lookup for it, but it’s directly stored and taken from the execution context).

  37. You should pack these articles a in book. They are just amazing. You made all these abstractions breeze to understand. Thank you again for this.

  38. @Dmitry
    I want to know the difference between lexical scope and variable scope, could you explain to me?

  39. @yezi

    I want to know the difference between lexical scope and variable scope, could you explain to me?

    The lexical environment is used when a function is created inside with block, or catch clause. Initially variable and lexical environments have the same data, however, variable environment never change, but the lexical environment may change during execution.

    Please see this section for detailed description.

  40. @Dmitry,
    Can you recommend some articles or books about how javaScript engine works to me? I want to know what happens in the precompiled stage and the execution stage, such as the creation of EC,VO(AO),this,scope chain and so on.

  41. @yezi, the documentation which fully describe how a JS engine should work is EMCMAScript specification. There you can find algorithms for every possible stage of a JS program execution. It is though very formal description for implementers, but still the source of truth of any JS-related question.

  42. So [[Scope]] is a queue or a stack? From the code sample:

    barContext.Scope = [
      barContext.AO,
      fooContext.AO,
      globalContext.VO
    ];
    

    Looks like last in first out.
    But from:

    var Scope = [VO1, VO2, ..., VOn]; // scope chain
    var VO1 = {__parent__: null, ... other data}; -->
    var VO2 = {__parent__: VO1, ... other data}; -->
    // etc.
    

    It looks like VO1.__parent__ should be pointing to VO2.__parent__VOn.__parent__ = null, where VOn is the global scope.

  43. Correction above, VO1.__parent__ = VO2, and VO2.__parent__ = VO3
    and VOn.__parent__ = null being the global scope.

  44. @Charles, I think a better representation is exactly a linked list with parent link (this is how environments are implemented in ES5 spec).

    So more of:

    theMostNested -> outer -> ... -> global -> null
    

    In terms of activation of the contexts (and a new environment is created whenever a new context is created), it’s of course a stack. But parent link of environments is not related to them: you may active 3 contexts pushing them onto the stack, and creating the environments for them (activation objects in ES3), then the contexts finish, and are popped from the stack, but the environment may stay in memory because of closure, which still will store it as a parent link from some other environment.

  45. Dear Dmitry.
    I would like to ask you does the function [[scope]] contain parent’s VO or just reference to parent’s VO?