Revised Answer:
Based on feedback from @Oriol concerning property attributes. I have found that the real issue here is concerning Property Attributes (See ECMA-262 edition 5.1 section 8.6.1) and the Variable Environment's execution context (See ECMA-262 edition 5.1 section 10.3)
Can anyone explain why Chrome behaves differently than Safari and
Firefox in this regard?
var one = 1;
delete one;
console.log(one); // Returns 1.. but why?
Two things are happening here:
- The
var declaration binds the declared object into an "Execution context" that is distinctly different from the Global (window) one.
- JavaScript evaluates the
[[Configurable]] property to determine if its "OK" to delete
Concerning #1
The var declaration in the code establishes a VariableEnvironment whereby the value is bound to the object in a distinctly different execution context (scope) than the global one. So naturally, when var is not used the VariableEnvironment is interpreted in a global execution binding process, making statements like one = 1; or delete one; possible.
var one = 1; // Execution context #1 has a unique VariableEnvironment
delete one; // Execution context #2 has a global VariableEnvironment
console.log(one); // Return the value from 'var one'
This complies with the language spec:
10.4 Establishing an Execution Context
Evaluation of global code or code using the eval function (15.1.2.1)
establishes and enters a new execution context...
10.4.2 Entering Eval Code
The following steps are performed when control enters the execution
context for eval code:
If there is no calling context or if the eval code is not being
evaluated by a direct call (15.1.2.1.1) to the eval function then,
Initialise the execution context as if it was a global execution
context using the eval code...
Concerning #2
Chrome and JSFiddle are both doing the right thing here. The the reason has to do with the [[Configurable]] property attribute, which is assigned to both native and user-created properties behind the scenes. When a user-created property is established, this attribute is set to true. This allows the developer to execute assign and delete commands on the property.
var test = {};
test.me = "OK" // [[Configurable]] is true so No Problem!
delete test.me // Good here too!
To prevent certain situations where object properties should not ever be deleted or modified [[Configurable]] is set to false by default. Which respects the language spec:
If the value of an attribute is not explicitly specified by this
specification for a named property, the default value defined in Table
7 is used...
[[Configurable]] false
var test2 = [1,2,3];
console.log(test2.length); // length property is '3'
console.log(delete test2.length); // NOPE [[Configurable]] is false
Same is true in function arguments in a function scope:
(function foo(one) {
console.log(delete one);
})(); // NOPE (false)
What can we draw from both findings?
From this we can understand that Firefox and Safari do not does not play by the rules. When var one=1; is declared in either of these browser's consoles, properties in this scope are incorrectly deemed [[Configurable]] by default and thus deletes var one and not the implied window.one.
In Firefox/Safari:
var one = 1; // var 'one'?
delete one; // NUKE var 'one'!
console.log(one); // ReferenceError: 'one' is not defined :'(
"OK Wait! So why then is delete one true by itself?
It plays out as determined by the language spec (10.4.2):
var one = 1; // VariableEnvironment not global or [[Configurable]]
delete one; // FALSE
...
delete one; // TRUE VariableEnvironment global and [[Configurable]]
...
var one = 1; // VariableEnvironment not global or [[Configurable]]
delete this.one; // TRUE VariableEnvironment is global and [[Configurable]]
deleteis supposed to be used.oneshould remain there with the value1sincedelete oneshouldn't do anything. Quoting from MDN:delete is only effective on an object's properties. It has no effect on variable or function names.deleteoperator is only useful to delete properties of an object, like this:delete someObject.fooordelete someObject[propName]