Variables vs. Properties in JavaScript

( 한국어 )

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

About these ads

19 thoughts on “Variables vs. Properties in JavaScript

  1. Pingback: Tweets that mention Variables vs. Properties in JavaScript « JavaScript, JavaScript -- Topsy.com

  2. Hi, thanks for really interesting reading. One question that I have is regarding declaring variables in eval, why they don’t get DontDelete attribute? What is the reason behind this? I understand that this is stated in standart but I can’t understand why it was done in this way.

    Thanks!

  3. Pingback: [번역] 자바스크립트에서 변수와 프로퍼티의 차이 | Inside jQuery

  4. Pingback: Compreendendo a palavra-chave this do JavaScript :: Top Tutoriais

  5. Pingback: 尚春 » [译]理解Javascript关键字this

  6. Under “What is a variable” you have:

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

    implying f is a global variable.

    But under “How many ways can I define a property?” you have:

    //forgetting to use the var keyword
    08 var bar = function() {
    09 foo = “hello”;
    10 }

    implying foo is a property (of window I assume).

    These two examples seem contradictory.

    (BTW I’m typing blind because your page doesn’t display correctly under IE8 — the login lines cover the text area.

    • Ok, I see a possible difference between

      function foo = function(){…

      and

      var bar = function(){…

      but not quite clear on exactly what.

  7. Pingback: Differences in function declarations in a Javascript constructor function - Programmers Goodies

  8. Pingback: Crockford on JavaScript – 2 – And Then There was JavaScript

  9. Pingback: Understanding JavaScript’s this keyword : Designer Devil

  10. “When you (explicitly) create a property, its [[DontDelete]] value is initially false.”
    Not entirely true.
    Object.defineProperty(this, ‘propOnObj1′, {
    value: ‘value of propOnObj1′
    // writable: false,
    // enumerable: false,
    // configurable: false,
    });

    delete propOnObj1; //false

  11. Pingback: JavaScript Properties « Binarymist

  12. An outstanding share! I’ve just forwarded this onto a friend who had
    been doing a little research on this. And he actually bought me lunch because I found
    it for him… lol. So allow me to reword this…. Thanks for the meal!!

    But yeah, thanx for spending time to discuss this matter
    here on your web page.

  13. Potentially useful if you rework your sketchy code samples–make them clear and complete so I can run them myself.

  14. Pingback: JavaScript: Abusing “this” | Latinforimagination

Leave a Reply

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

WordPress.com Logo

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

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s