( 한국어 )
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
Another great post Angus! Thanks for doing these.
Marc, glad you liked it!
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!
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.
“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
Hi
I tried your example but i am getting undefined in global contect. Could you tell me a reason for this.
You can use this fiddle
http://jsfiddle.net/wTg9N/1/
Thanks in advance!
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.
Potentially useful if you rework your sketchy code samples–make them clear and complete so I can run them myself.
“function foo = function(){…}”
I think you have a syntax error there.
Should be var foo = function(){…} or function foo(){…}