ECMA-262-3 in detail. Chapter 2. Variable object.
Read this article in: Russian, Chinese (version1, version2).
Introduction
Always in programs we declare functions and variables which then successfully use building our systems. But how and where the interpreter finds our data (functions, variable)? What occurs, when we reference to needed objects?
Many ECMAScript programmers know that variables are closely related with the execution context:
var a = 10; // variable of the global context
(function () {
var b = 20; // local variable of the function context
})();
alert(a); // 10
alert(b); // "b" is not defined
Also, many programmers know that the isolated scope in the current version of specification is created only by execution contexts with “function” code type. I.e., in contrast with C/C++, for example the block of for loop in ECMAScript does not create a local context:
for (var k in {a: 1, b: 2}) {
alert(k);
}
alert(k); // variable "k" still in scope even the loop is finished
Let’s see in more details what occurs when we declare our data.
Data declaration
If variables are related with the execution context, it should know where its data are stored and how to get them. This mechanism is called as variable object.
- variables (var, VariableDeclaration);
- function declarations (FunctionDeclaration, in abbreviated form FD);
- and function formal parameters
declared in the context.
Schematically and for examples, it is possible to present variable object as normal ECMAScript object:
VO = {};
And as we said, VO is a property of the execution context:
activeExecutionContext = {
VO: {
// context data (var, FD, function arguments)
}
};
Indirect referencing to variables (via property names of VO) allows only variable object of the global context (where the global object is itself the variable object, but about it a bit later). For other contexts directly to reference the VO is not possible; it is purely mechanism of implementation.
When we declare a variable or a function, there is nothing else as creation of the new property of the VO with the name and value of our variable.
Example:
var a = 10;
function test(x) {
var b = 20;
};
test(30);
And corresponding variable objects are:
// Variable object of the global context
VO(globalContext) = {
a: 10,
test: <reference to function>
};
// Variable object of the "test" function context
VO(test functionContext) = {
x: 30,
b: 20
};
But at implementation level (and specification) the variable object is an abstract essence. Physically, in concrete execution contexts, VO is named differently and has different initial structure.
Variable object in different execution contexts
Some operations (e.g. variable instantiation) and behavior of the variable object are common for all execution context types. From this viewpoint it is convenient to present the variable object as an abstract base thing. Function context can also define additional details related with the variable object.
AbstractVO (generic behavior of the variable instantiation process)
║
╠══> GlobalContextVO
║ (VO === this === global)
║
╚══> FunctionContextVO
(VO === AO, <arguments> object and <formal parameters> are added)
Let’s consider it in detail.
Variable object in global context
Here, first it is necessary to give definition of the Global object.
Global object is the object which is created before entering any execution context; this object exists in the single copy, its properties are accessible from any place of the program, the life cycle of the global object ends with program end.
At creation the global object is initialized by such properties as Math, String, Date, parseInt etc., and also by additional objects among which can be the reference to the global object itself — for example, in DOM, window property of the global object refers to global object (however, not in all implementations):
global = {
Math: <...>,
String: <...>
...
...
window: global
};
When referencing to properties of global object the prefix is usually omitted, because global object is not accessible directly by name. However, to get access to it is possible via this value in the global context, and also through recursive references to itself, for example window in DOM, therefore write simply:
String(10); // means global.String(10); // with prefixes window.a = 10; // === global.window.a = 10 === global.a = 10; this.b = 20; // global.b = 20;
So, coming back to variable object of the global context — here variable object is the global object itself:
VO(globalContext) === global;
It is necessary to understand accurately this fact since for this reason declaring a variable in the global context, we have ability to reference it indirectly via property of the global object (for example when the variable name is unknown in advance):
var a = new String('test');
alert(a); // directly, is found in VO(globalContext): "test"
alert(window['a']); // indirectly via global === VO(globalContext): "test"
alert(a === this.a); // true
var aKey = 'a';
alert(window[aKey]); // indirectly, with dynamic property name: "test"
Variable object in function context
Regarding the execution context of funcitons — there VO is inaccessible directly, and its role plays so-called an activation object (in abbreviated form — AO).
VO(functionContext) === AO;
Activation object is created on entering the context of a function and initialized by property arguments which value is the Arguments object:
AO = {
arguments: <ArgO>
};
Arguments objects is the property of the activation object of a function context. It contains the following properties:
- callee — the reference to the current function;
- length — quantity of real passed arguments;
- properties-indexes (integer, converted to string) which values are the values of function’s arguments (from left to right in the list of arguments). Quantity of these properties-indexes == arguments.length. Values of properties-indexes of the arguments object and present (really passed) formal parameters are shared.
Example:
function foo(x, y, z) {
alert(arguments.length); // 2 – quantity of passed arguments
alert(arguments.callee === foo); // true
alert(x === arguments[0]); // true
alert(x); // 10
arguments[0] = 20;
alert(x); // 20
x = 30;
alert(arguments[0]); // 30
// however, for not passed argument z,
// related index-property of the arguments
// object is not shared
z = 40;
alert(arguments[2]); // undefined
arguments[2] = 50;
alert(z); // 40
}
foo(10, 20);
Concerning the last case, in current version of Google Chrome there is a bug — there parameter z and arguments[2] are also shared.
Phases of processing the context code
Now we have reached the main point of this article. Processing of the execution context code is divided on two basic stages:
- Entering the execution context;
- Code execution.
Modifications of the variable object are closely related with these two phases.
Notice, that processing of these two stages are the general behavior and independent from the type of the context (i.e. it is fair for both: global and function contexts).
Entering the execution context
On entering the execution context (but before the code execution), VO is filled with the following properties (they have already been described at the beginning):
- for each formal parameter of a function (if we are in function execution context)
- for each function declaration (FunctionDeclaration, FD)
- for each variable declaration (var, VariableDeclaration)
— a property of the variable object with a name and value of formal parameter is created; for not passed parameters — property of VO with a name of formal parameter and value undefined is created;
— a property of the variable object with a name and value of a function-object is created; if the variable object already contains a property with the same name, replace its value and attributes;
— a property of the variable object with a variable name and value undefined is created; if the variable name is the same as a name of already declared formal parameter or a function, the variable declaration does not disturb the existing property.
Let’s see on the example:
function test(a, b) {
var c = 10;
function d() {}
var e = function _e() {};
(function x() {});
}
test(10); // call
On entering the “test” function context with the passed parameter 10, AO is the following:
AO(test) = {
a: 10,
b: undefined,
c: undefined,
d: <reference to FunctionDeclaration "d">
e: undefined
};
Notice, that AO does not contain function “x”. This is because “x” is not a function declaration but the function-expression (FunctionExpression, in abbreviated form FE) which does not affect on VO. However, function “_e” is also the function-expression, but as we will see below, because of assigning it to the variable “e”, it becomes accessible via the “e” name. The difference FunctionDeclaration from FunctionExpression is in detail discussed in Chapter 5. Functions.
And after that there comes the second phase of processing of a context code — the code execution stage.
Code execution
By this moment, AO/VO is already filled by properties (though, not all of them have the real values passed by us, most of them yet still have initial value undefined).
Considering all the same example, AO/VO during the code interpretation is modified as follows:
AO['c'] = 10; AO['e'] = <reference to FunctionExpression "_e">;
Once again I notice that FunctionExpression “_e” is still in memory only because it is saved to declared variable “e”. But the FunctionExpression “x” is not in the AO/VO: i.e., if we try to call “x” function before or after definition — there will be an error “x is not defined”. Unsaved FunctionExpression can be called only with its definition or recursively.
One more (classical) example:
alert(x); // function
var x = 10;
alert(x); // 10
x = 20;
function x() {};
alert(x); // 20
Why in the first alert “x” is a function and moreover is accessible before the declaration? Why is not 10 or 20? Because, according to the rule — VO is filled with function declarations on entering the context; at the same phase, on entering the context, there is a variable declaration “x”, but as we mentioned above the step of variable declarations semantically goes after function and formal parameters declarations and on this phase do not disturb the value of the already declared function or formal parameter with the same name, therefore, on entering the context VO is filled as follows:
VO = {};
VO['x'] = <reference to FunctionDeclaration "x">
// found var x = 10;
// if function "x" would not be already defined
// then "x" be undefined, but in our case
// variable declaration does not disturb
// the value of the function with the same name
VO['x'] = <the value is not disturbed, still function>
And then at code execution phase, VO is modified as follows:
VO['x'] = 10; VO['x'] = 20;
what we can see in the second and third alerts.
In the example below we see again that variables are put into the VO on entering the context phase (so, the else block is never executed, but nevertheless, the variable “b” exists in VO):
if (true) {
var a = 1;
} else {
var b = 2;
}
alert(a); // 1
alert(b); // undefined, but not "b is not defined"
About variables
Often various articles and even books on JavaScript claim that: “it is possible to declare global variables using var keyword (in the global context) and without using var keyword (in any place)”. It is not so. Remember:
variables are declared only with using var keyword.
And assignments like:
a = 10;
just create the new property (but not the variable) of the global object. “Not the variable” is not in the sense that it cannot be changed, but “not the variable” in concept of variables in ECMAScript (which then also become properties of the global object because of VO(globalContext) === global, we remember, yeah?).
And the difference is the following (let’s show on the example):
alert(a); // undefined alert(b); // "b" is not defined b = 10; var a = 20;
All again depends on VO and phases of its modifications (entering the context stage and the code execution stage):
Entering the context:
VO = {
a: undefined
};
We see that at this phase there is no any “b” since it is not a variable, “b” will appear only at code execution phase (but in our case won’t since there is an error).
Let’s change the code:
alert(a); // undefined, we know why b = 10; alert(b); // 10, created at code execution var a = 20; alert(a); // 20, modified at code execution
There is one more important point concerning variables. Variables, in contrast with simple properties, have attribute {DontDelete}, meaning impossibility to remove property via the delete operator:
a = 10; alert(window.a); // 10 alert(delete a); // true alert(window.a); // undefined var b = 20; alert(window.b); // 20 alert(delete b); // false alert(window.b); // still 20
But there is one execution context on which this rule does not affect; it is the eval context: there {DontDelete} attribute is not set for variables:
eval('var a = 10;');
alert(window.a); // 10
alert(delete a); // true
alert(window.a); // undefined
For those who test these examples in console of some debug tool, e.g. Firebug: notice, that Firebug also uses eval to execute your code from the console. So there vars also do not have {DontDelete} and can be deleted.
Feature of implementations: property __parent__
As it was already noted, by the standard, to get direct access to the activation object is impossible. However, in some implementations, namely in SpiderMonkey and Rhino, functions have special property __parent__, which is the reference to the activation object (or the global variable object) in which these functions have been created.
Example (SpiderMonkey, Rhino):
var global = this;
var a = 10;
function foo() {}
alert(foo.__parent__); // global
var VO = foo.__parent__;
alert(VO.a); // 10
alert(VO === global); // true
In the example above we see that function foo is created in the global context and, accordingly, its __parent__ property is set to variable object of the global context, i.e. to the global object.
However, to get the activation object in SpiderMonkey with the same way is not possible: depending on the version, __parent__ for inner function returns either null or global object.
In Rhino, access to the activation object is allowed and available via the same way:
Example (Rhino):
var global = this;
var x = 10;
(function foo() {
var y = 20;
// the activation object of the "foo" context
var AO = (function () {}).__parent__;
print(AO.y); // 20
// __parent__ of the current activation
// object is already the global object,
// i.e. the special chain of variable objects is formed,
// so-called, a scope chain
print(AO.__parent__ === global); // true
print(AO.__parent__.x); // 10
})();
Conclusion
In this article we have moved further forward in studying of objects related with execution contexts. I hope the material is useful and has clarified some aspects and ambiguities which, probably, you had before. Further by the plan, the next chapters will be devoted to the Scope chain, Identifier resolution and, as consequence, Closures.
If you have questions, I will answer them with pleasure in comments.
Additional literature
- 10.1.3 – Variable Instantiation;
- 10.1.5 – Global Object;
- 10.1.6 – Activation Object;
- 10.1.8 – Arguments Object.
Translated by: Dmitry A. Soshnikov.
Published on: 2010-03-15
Originally written by: Dmitry A. Soshnikov [ru, read »]
Originally published on: 2009-06-27
Tags: Activation object, ECMA-262-3, ECMAScript, Variable object

15. March 2010 at 23:50
Nice writeup. By VO you mean the Reference I assume?
16. March 2010 at 14:29
@qFox
Thanks; about VO — this is a just my abbreviation for “Variable object”; for shortness, not to repeat every time “variable object” phrase as there are to many in this text. Also, it is convenient to use in formulas and talks (e.g. saying that current scope chain is a VO|AO + [[Scope]] — which means, that variable/activation object is added in front of parent scope chain).
About “Reference” — what exactly do you mean? Yes, it is a reference to object, but VO|AO — is a purely implementation mechanism; only VO of global context is accessible directly and as implementation feature — AO in Rhino. Or maybe you meant Reference type? If so, VO|AO can be used as a base property of Reference type value.
Dmitry.
17. March 2010 at 03:25
excelent articles If you have in mind to translate in spanish maybe I can help
thanks for the info
17. March 2010 at 12:09
@Juan Anzaldo
Thanks, Juan. Yes, it is possible to translate it to Spanish (I’m glad to see that there are many Spanish guys interested deeply in ECMAScript). But unfortunately I don’t know Spanish at all. So if you take care about the English => Spanish translation, I’ll help with detailed explanations (or with clarifying of ambiguities) if will be needed.
Dmitry.
12. April 2010 at 20:50
So that’s why
vars should go at the beginning of scripts!These articles are awesome.
12. April 2010 at 21:29
@Alejandro Moreno
Yep, sometimes it is convenient to define all
vars at the beginning, because anyway they all are parsed on entering the context.But for some
vars it is also useful to declare them at the code position where they are used (e.g. loop counters) — just because it’s convenient and you don’t want to see all auxiliary helper variables at the beginning if e.g. you exit the code in the first line if some check isn’t passed. Although one should keep in mind that variable still will be available after the loop is finished.Dmitry.
18. April 2010 at 17:26
Good article,I have learned a lot form here. So I translate it into Chines:
ECMA-262-3 深入解析.第二章.变量对象
thank you!
18. April 2010 at 17:35
@denisdeng
Thanks, that’s great. Added a link to your translation.
18. April 2010 at 17:39
Thank you! I will translate the next chapters as soon as possible。
22. April 2010 at 09:30
I have a question:
“properties-indexes (integer, converted to string) “,
I think you want to say:
“properties-indexes [integer, converted to string]”
it’s difference at “()” or “[]”
Do you think my understanding correct?
22. April 2010 at 12:09
@justin
Oh, nope, in that sentence was mentioned not a code expression, but just simple grammar punctuation. I notice there what exactly is an “index-property” (or “array-index” which is described in 15.4 of ES3 spec). Because ES3 has only properties and these properties can be only strings.
I could change it to array indexes definition (because ES3 has such concept), but then arguments object could be treated as an array instance, but it is not (although, I think that it is an error of the spec and arguments should be an array).
And “()” — was just a wording grammar punctuation there.
Dmitry.
22. April 2010 at 12:52
I understand, thank you!
Another problem:
“It is convenient to present variable object as base abstract essence from which concrete sub essences playing role of variable object in different execution contexts are “inherited””
This passage is not easy to understand, not easy to translate.
Here is my translate:
Chinese:
变量对象作为基本抽象事物来表现是很方便的,具体子事物是抽象事物的具体实现,具体子事物在不同的执行上下文中扮演着变量对象的角色,它们是“可继承” 的;
English:
Variable objects to represent things as the basic abstraction is very convenient;
Specific sub-things are abstract and concrete realization of things;
Specific sub-things in a different execution context play the role of the variables object.
For example:
AO is VO’s concrete realization in function execution context;
AO === Specific sub-things
VO === the basic abstraction things
Do you think my understanding correct?
22. April 2010 at 12:55
AO inherite form VO?
22. April 2010 at 14:42
@justin
Yep, that exactly I meant. Yes, “inherited” word was a little confusing, so I removed it. Added an example illustration to make it easier to represent.
“Inherit” meant mostly that there is some common behavior (i.e. variable instantiation process) which is independent from the execution context type, but at the same time different execution context types can define their own initial structure of VO (e.g. arguments object and formal parameters of a function) and moreover, use different object as storage for variable instantiation: in global context — it is global object itself, in function context — it is an activation object.
Dmitry.
22. April 2010 at 19:36
VO/AO,I understand that, thank you very muck!
one more question:)
” but“not the variable” in concept of variables in ECMAScript“
This passage is not easy to understand,I think your meant is :
because it does not meet the concept of variable in ECMAScript standard, so it “is not a variable”
Correct?
22. April 2010 at 21:03
@justing
Yep, correct. The main goal that variables in ECMAScript (1) cannot be deleted (except the eval context) with using of delete operator and (2) instantiated on entering the context. Exactly these two facts were meant in sentence “is a variable in concept of variables in ECMAScript”.
Meanwhile, unqualified identifiers of the global object (i.e. simple assignment to non-existent yet identifier, such as: a = 10) — not: they can be deleted and created at code execution stage.
Dmitry.
23. April 2010 at 14:05
Thanks so much, through this article I learned a lot!
After disscussing with you,I think I have understood this article totally , and also translated it into Chinese .
I’m sure my translation is more nearly to this excellent article.
here it is : http://www.cnblogs.com/justinw/archive/2010/04/23/1718733.html
23. April 2010 at 14:45
@justin
OK, I will add the second version of Chinese translation for this chapter. Also you can discuss it with Denis (which also provides translations) about this question. Because I, unfortunately, can’t say which Chinese translation is better (because don’t know Chinese at all) and automatic Google-translate also cannot provide such info for me.
Dmitry.
23. April 2010 at 15:24
I understand, thanks!
23. April 2010 at 15:33
I have a suggestion
If the article is updated, it is best to maintain an update log
then facilitate future updates Other languages
23. April 2010 at 17:12
@justin
In some other articles I would make something like “updated on <date>“. What actually I did in comments of e.g. The Quiz article when was changing some questions (because it was important for those who already passed the test with previous questions).
But this series is academical so I don’t want to break article descriptions with some update, update, update words. It should be complete and up-to-date information without breaking the text itself.
But for own purposes (and to keep translations also up-to-date) — yeah, I’ll think about it and maybe will make sort of subversion repository for that.
Dmitry.