修改后的答案:
基于@Oriol 关于属性属性的反馈。我发现这里真正的问题是关于 Property Attributes(参见 ECMA-262 edition 5.1 section 8.6.1)和 Variable Environment 的执行上下文(参见 ECMA-262 edition 5.1 section 10.3)
谁能解释为什么 Chrome 的行为与 Safari 不同?
火狐在这方面呢?
var one = 1;
delete one;
console.log(one); // Returns 1.. but why?
这里发生了两件事:
-
var 声明将声明的对象绑定到与全局 (window) 明显不同的“执行上下文”。
- JavaScript 评估
[[Configurable]] 属性以确定其是否“可以”删除
关于#1
代码中的var 声明建立了一个VariableEnvironment,其中值绑定到与全局上下文截然不同的执行上下文(范围)中的对象。所以很自然,当不使用var 时,VariableEnvironment 会在全局执行绑定过程中进行解释,从而使one = 1; 或delete one; 之类的语句成为可能。
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'
这符合语言规范:
10.4 建立执行上下文
使用 eval 函数评估全局代码或代码 (15.1.2.1)
建立并进入一个新的执行上下文...
10.4.2 输入评估码
控制进入执行时执行以下步骤
评估代码的上下文:
如果没有调用上下文或者 eval 代码没有被调用
然后通过对 eval 函数的直接调用 (15.1.2.1.1) 进行评估,
初始化执行上下文,就好像它是全局执行一样
使用 eval 代码的上下文...
关于#2
Chrome 和JSFiddle 都在做正确的事情。原因与[[Configurable]] 属性有关,该属性在后台分配给本机和用户创建的属性。建立用户创建的属性时,此属性设置为true。这允许开发人员对属性执行分配和删除命令。
var test = {};
test.me = "OK" // [[Configurable]] is true so No Problem!
delete test.me // Good here too!
为了防止某些情况下不应删除或修改对象属性,[[Configurable]] 默认设置为false。尊重语言规范:
如果一个属性的值没有明确指定
命名属性的规范,表中定义的默认值
7用了……
[[可配置]] 错误
var test2 = [1,2,3];
console.log(test2.length); // length property is '3'
console.log(delete test2.length); // NOPE [[Configurable]] is false
函数范围内的函数参数也是如此:
(function foo(one) {
console.log(delete one);
})(); // NOPE (false)
我们可以从这两个发现中得出什么结论?
由此我们可以了解到,Firefox 和 Safari 并不是不按规矩办事的。当var one=1; 在这些浏览器的控制台中声明时,此范围内的属性默认被错误地视为[[Configurable]],因此删除var one 而不是隐含的window.one。
在 Firefox/Safari 中:
var one = 1; // var 'one'?
delete one; // NUKE var 'one'!
console.log(one); // ReferenceError: 'one' is not defined :'(
“好吧等等!那为什么delete one本身就是真的?
它的表现由语言规范 (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]]