Compare this code1:
somevar = 5;
delete window.somevar;
alert(typeof somevar) //=> undefined, so deleted
to this code:
var somevar = 5;
delete window.somevar;
alert(typeof somevar) //=> number, so NOT deleted
See it in action here
Now in the first block, somevar
is deleted, in the second block it's not. The only difference is using the var
keyword in the second block. Both blocks run in the global scope.
Can this be explained?
1 the code can't be tested in a chrome-console or firebug, and not in jsfiddle either. In those environments all code is evalled
, and in evalled code delete
works on anything that is the result of eval
(see more about that). In IE < 9 delete window[anything]
is not allowed anyway.
What you're seeing is an aspect of the fact that the global object (window
, on browsers) is a conflation of two different things which are distinct everywhere except the global execution context.
In the first block, someVar
is a normal property of the window
object. Properties can be removed via delete
.
In the second block, someVar
is a property of the binding object of the variable context of the global execution context — which is also window
. You cannot delete properties the binding object receives in its role as the binding object (even though you can delete properties it receives in other ways). That is, you cannot delete variables declared with var
(and a few other things that are added the same way).
(Sorry, not my terminology; it comes from the spec, which features some very fun language indeed.)
It's only the global execution context where we have this conflation of concepts. The variable binding object for other execution contexts (function calls, for instance) is still a very real thing (and crucial to proper functioning of closures), but there's no programmatic way to directly access it. In the global execution context, though, it's the global object, which of course we can access.
It helps to understand this if we look at functions first, and then look at the global execution context. when you call a function, these things happen:
this
to point to the object designated by the call (the value of this
is usually implicitly set, but there are ways to set it explicitly).arguments
property to the binding object, referring to the pseudo-array of arguments to the function.var
statements (anywhere in the function body) as properties of the binding object, initially with the value undefined
....and then step-by-step execution of the code in the body of the function begins. Any var
statements with initializers (e.g., var a = 5;
rather than just var a;
are treated as assignment statements (a = 5;
) when the execution point reaches them.
Throughout the above, whenever a property is added "to the binding object", it's added with a flag indicating that it cannot be deleted. This is why var
s (and the names of declared functions, etc.) can't be deleted.
Any unqualified reference is looked up via the scope chain. So when you refer to a
in your code, the first place the interpreter looks is the binding object at the top of the scope chain. If it has a property called a
, that's what gets used; if not, we look at the next link down the scope chain and use that property if we find it; and so on until we run out of links on the scope chain. The global object is the bottommost link of that chain (which is why global variables work).
So what's different about the global context? Well, very little, actually. Here's the sequence (roughly):
this
to point to the binding object; that makes it the global object.window
is added to the object, referring to itself)....and then we basically pick up with step 8 in the function stuff:
var
statements (anywhere in the global scope) as properties of the binding/global object, initially with the value undefined
....and start step-by-step execution of the code (again with var
initializers becoming assignments).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With