( 한국어 )

What is a property? What is a variable? In what ways, if any, do they differ?

Basic questions. Fundamental to understanding the language, but mostly overlooked in the literature of JavaScript. (That said, I know of two excellent articles on the topic. I’ve cited them at the end of this text)

Anyway, here’s my take on it:



The VariableObject

In order to understand what a JavaScript variable is we need to know about the VariableObject. In JavaScript, code can be executed within the global or functional context. There is only one global context. There is one functional context per function call. (There is also a third case – eval context which we’ll touch on later). Each execution context has an associated VariableObject. Variables (and functions) created within a given context exist as properties of that context’s VariableObject.

The global context’s VariableObject is the global object. In a browser thats window :

var a = "hello"; //window is the global VariableObject window.a; //hello

In the functional context its trickier. Each function context has a VariableObject (in this context known as an ActivationObject) but you can’t access it (unless you’re using Rhino). You just need to know that its there. Hence when you create a variable within a function context you can’t reference it as a property.

function foo() { var bar = "sausage"; window.bar; //undefined (VariableObject is not window) }

OK so now we can ask some questions:

What is a property?

ECMA 5: An association between a name and a value that is a part of an object. [4.3.26]

In other words, properties are the building blocks of objects.

//Examples of properties foo.bar = "baz"; window.alert; a.b = function(c,d,e) {return (c * d) + e}; Math.PI; myArray[5];

What is a variable?

Unfortunately ECMA5 does not oblige us with a definition here.

Lets try this: An association between a name and a value that exists within an execution context

Already we can see the essential difference emerging. Properties belong to objects; Variables belong to contexts (and context happens to have an object representation – the VariableObject).

//Examples of variables var bar = 2; //global context function foo = function() { var a; //function context f = 4; //global context (probably unintentionally) }

But variables and properties are interchangeable right?

Not really, although it might appear that way:

//define as a property, access as a variable window.foo = "a"; foo; //a //define as a variable, access as a property var bar = 54; window.bar; //54

This only works because the global object (parent of properties) and the global VariableObject (parent of variables) happen to be the same. In the function context, of course, property/variable switching will fail.

Ok, so why should I care?

There are several behavioural differences that will influence object composition and program flow. (Thank you to Dmitry Soshnikov for summarizing these issues)

hoisting

I wrote about hoisting at length in a previous posting. It boils down to this. Objects defined by variable declarations and function declarations get created (i.e. added to the VariableObject) at the beginning of the execution scope. On the other hand property definitions get created only when control reaches the containing statement.

alert(a); //undefined (no error) alert(b); //ReferenceError: b is not defined var a = 24; window.b = 36;

Two things to note:

1) Variable a is hoisted but not its value (contrast with hositing of FunctionDeclarations)

2) We could have avoided the ReferenceError by simply accessing b by property syntax window.b . When confronted with b without an object qualifier JavaScript assumes we are referencing a variable and so checks its VariableObject (which has no property named b ) When an identifier is not found in the VariableObject we get a ReferenceError. Conversely simple property accessors will return the result of a hash lookup on the parent object (in this case the value undefined ). More on ReferenceErrors in my next post.

attribute initialization

Every new property gets a property descriptor by default. The property descriptor defines several property attributes ([[value]] is the most visible) . ECMA 3 reserved most of these attributes for internal use: {DontDelete}, {DontEnum}, {ReadOnly}. In ECMA 5 these attribute names have changed to describe the contrary cases: [[Writable]], [[Enumerable]] and [[Configurable]]. According to ECMA 5 they are also to some extent externally modifiable. (For more on this topic please read this article by Dmitry Soshnikov Also thanks to Dmitry for pointing out typos and format errors)

For simplicity I will focus on the one attribute that is pertinent to this discussion, and I will use the ECMA 3 definition: [[DontDelete]].

When you create a variable it’s [[DontDelete]] attribute is set to true. When you (explicitly) create a property, its [[DontDelete]] value is initially false.

//variable var oneTimeInit = function() { //do stuff } delete oneTimeInit; //false (means it did not happen) typeof oneTimeInit; "function"; //explicit property window.oneTimeInit = function() { //do stuff } delete oneTimeInit; //true typeof oneTimeInit; "undefined";

For full details on delete as it applies to variables and properties check out this priceless article by kangax. He also explains why Firebug appears to let you delete a variable.

illegal names

By using subscript notation (square brackets) we can endow properties, but not variables, with illegal identifier names (ECMA 5, 7.6)

//illegal name var a = "***"; window[a] = 123; window[a]; //123 (Property lookup OK) *** //ReferenceError (illegal name) //legal name var a = "foo"; window[a] = 123; window[a]; //123 foo; //123

What other kinds of variables are there?

The function’s arguments object, and each formal parameter will also be added to the ActivationObject (i.e. the VariableObject of the function). Function declarations are also properties of this object so can in a sense be considered variables.

How many ways can I define a property?

At least five.

//dot notation window.foo = 'hello'; //subscript notation window['foo'] = 'hello'; //forgetting to use the var keyword var bar = function() { foo = "hello"; } //Using ECMA 5 methods (showing limited use of property attributes for clarity) //runs in chrome, safari and IE8 (IE8 works for DOM objects only) Object.defineProperty(window,"foo", {value: "hello"}); //runs in chrome and safari Object.defineProperties(window, {"foo": {value: "hello"},"bar": {value: "goodbye"}});

What about the evaluation context?

Ok so when JavaScript runs code defined as an argument to the eval function it adopts the execution context in which the eval statement is contained (ECMA 5 10.4.2). Consequently, variables defined within eval code become properties of the containing VariableObject.

In the following example – both foo , bar and blah are properties of the ActivationObject for function baz :

var baz = function(blah) { var foo = 34 * blah; eval('var bar =' + MY_SPECIAL_CODE); }

Also worth noting: Variables created within the eval context get their [[DontDelete]] attribute set to false (or the ECMA 5 equivalent).

eval('var bar = ' + n); delete bar; //true typeof bar; //undefined

(The Firebug console runs in the eval context which is why you can delete variables created in firebug)

Where can I find more information?

Juriy Zaytsev (“kangax”): Understanding Delete

Dmitry A. Soshnikov: ECMA-262-3 in detail. Chapter 2. Variable object.

Dmitry A. Soshnikov:

ECMA-262-5 in detail. Chapter 1. Properties and Property Descriptors.

ECMA 5:

Section 4.3.26 Definition of property

Section 8.6.1 Property Attributes

Section 10.5 Declaration Binding Instantiation (ECMA 5 refers to the VariableObject as the VariableEnvironment)

Section 15.2.3.6 Object.defineProperty

Section 15.2.3.7 Object.defineProperties