Here is the issue:
var x = 5;
window.x === x // true. x, as it seems, is a property of window
delete x; // false
delete window.x; // false;
This is how I understand that:
var x = 5;
declared in the global scope creates the new window
property x
.
window.x = 5;
declared (whereever) creates the new window property x
as well. That's why window.x === x
gives you true
.
The difference is that javascript by default sets different descriptors for x
property according to the way (one of two above) it is declared.
var x = 5
is equal to:
Object.defineProperty(window,'x',{
value: 5,
writable: true,
enumerable: true,
configurable: false
});
while window.x = 5
is equal to:
Object.defineProperty(window,'x',{
value: 5,
writable: true,
enumerable: true,
configurable: true
});
The configurable
descriptor, if false
, forbides to delete
the property.
We can assume, that javascript use Object.defineProperty
with different descriptor settings under the hood when we declare variables in a simple way with var
keyword or without it (automatically assigned to window
).
You can simply check that:
var x = 5;
window.y = 5;
console.log(Object.getOwnPropertyDescriptor(window,'x')); //configurable:false
console.log(Object.getOwnPropertyDescriptor(window,'y')); //configurable:true
Essentially the reason is that declared variables are created with an internal DontDelete
attribute, while properties created via assignment are not.
Here is great article explaining the inner details of delete
: Understanding delete
When declared variables and functions become properties of a Variable object — either Activation object (for Function code), or Global object (for Global code), these properties are created with DontDelete attribute. However, any explicit (or implicit) property assignment creates property without DontDelete attribute. And this is essentialy why we can delete some properties, but not others:
You can use delete
only for deleting objects, object properties or array element.
delete expression
delete
will be not working if expression can't be represented
as property. So delete
can remove global variable, but not variables inited by var
.
So, let me explain:
var x = 5;
You create variable in global scope by var, not property of window object. This var is just linked to window.x. And then you compare window.x === x
it will return true. But:
delete x; // deleting variable, not property, return false
delete window.x; // resolve link to x and also deleting variable, not property, return false
BUT
window.x = 5;//add property
delete window.x; // can delete property, return true
AND
window.x = 5;//add property
delete x; //resolve x. it's a propery of window, return true
and older
In ECMAScript 262/3 as @Peter explain is available DontDelete
flag. But in ECMAScript 262/5.1 in strict mode deleting is regulated by Configurable
flag:
When a delete operator occurs within strict mode code, a SyntaxError exception is thrown if its UnaryExpression is a direct reference to a variable, function argument, or function name. In addition, if a delete operator occurs within strict mode code and the property to be deleted has the attribute { [[Configurable]]: false }, a TypeError exception is thrown.