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
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,
someVaris a normal property of thewindowobject. Properties can be removed viadelete.In the second block,
someVaris a property of the binding object of the variable context of the global execution context — which is alsowindow. 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 withvar(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:
thisto point to the object designated by the call (the value ofthisis usually implicitly set, but there are ways to set it explicitly).argumentsproperty to the binding object, referring to the pseudo-array of arguments to the function.varstatements (anywhere in the function body) as properties of the binding object, initially with the valueundefined.…and then step-by-step execution of the code in the body of the function begins. Any
varstatements with initializers (e.g.,var a = 5;rather than justvar 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
vars (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
ain your code, the first place the interpreter looks is the binding object at the top of the scope chain. If it has a property calleda, 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):
thisto point to the binding object; that makes it the global object.windowis added to the object, referring to itself).…and then we basically pick up with step 8 in the function stuff:
varstatements (anywhere in the global scope) as properties of the binding/global object, initially with the valueundefined.…and start step-by-step execution of the code (again with
varinitializers becoming assignments).