我计划在JavaScript中使用delete运算符,当我决定通过使用它来提醒自己它是如何工作的时候。我理解"删除"应该在对象属性上使用,但我想看看它在变量上的行为方式。但是,当我将以下代码片段放在不同的浏览器中时,会出现一些奇怪的结果:
var one = 1;
delete one;
console.log(one); // prints out 1 in Chrome, but not in Safari or Firefox
在Safari中,JavaScript控制台打印出错误" ReferenceError:找不到变量:one"。 Firefox给出了类似的响应:" ReferenceError:一个未定义"。但是,Chrome打印出变量的值,1。有人可以解释为什么Chrome在这方面的行为与Safari和Firefox不同吗?
答案 0 :(得分:3)
不要信任控制台。有些代码在那里表现不同。
如果您在真实页面上运行,以下内容将提示1:
var one = 1;
delete one;
alert(one);
(在Firefox,Chrome,IE,Safari和Opera上测试过。)
Understanding delete解释了控制台(或萤火虫)显示不同行为的原因:
每个执行上下文都有一个所谓的变量对象关联 用它。与执行上下文类似,Variable对象是一个 抽象实体,一种描述变量实例化的机制。现在, interesing部分是在a中声明的变量和函数 源文本实际上是添加为此Variable对象的属性。
最后,在Eval代码中声明的变量被创建为属性 调用上下文的变量对象。
当声明的变量和函数成为变量的属性时 object - 激活对象(用于功能代码)或全局 对象(对于全局代码),这些属性是使用DontDelete创建的 属性即可。但是,任何显式(或隐式)属性赋值 创建属性而不使用DontDelete属性。这是必要的 为什么我们可以删除一些属性,而不是其他属性。
那么Firebug会发生什么?为什么声明变量 可以删除控制台,与我们刚刚学到的相反?好, 正如我之前所说,Eval代码有一个特殊的行为 变量声明。在Eval代码中声明的变量实际上是 创建为没有DontDelete的属性。
答案 1 :(得分:2)
Let's checkout the docs on delete
from MDN.
删除操作符从对象中删除属性。
您使用的方式没有多大意义,即删除局部变量。
那些文档也说:
如果属性是自己的不可配置属性,则以严格模式抛出(在非严格中返回false)。在所有其他情况下返回true。
这意味着您在此处的使用会在严格模式下抛出异常,因为您以不受支持的方式使用delete
。这可以在您做到时证明:
var one = 1;
delete one; // returns false
正如文档所提到的,返回值为false
表示delete
操作未成功。
如果你正确使用它,它应该表现得像你期望的那样:
var obj = {one: 1};
delete obj.one; // returns true
alert(obj.one); // alerts "undefined"
答案 2 :(得分:-1)
基于@Oriol关于属性属性的反馈。我发现这里真正的问题是关于属性属性(参见ECMA-262 edition 5.1 section 8.6.1)和变量环境的执行上下文(参见{{3 }})
任何人都可以解释为什么Chrome的行为与Safari和 Firefox在这方面?
var one = 1;
delete one;
console.log(one); // Returns 1.. but why?
这里发生了两件事:
var
声明将声明的对象绑定到"执行上下文"这与全球(window
)明显不同。[[Configurable]]
属性以确定其是否为" OK"删除代码中的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代码 通过直接调用(15.1.2.1.1)评估到eval函数, 初始化执行上下文,就好像它是全局执行一样 上下文使用eval代码......
Chrome和ECMA-262 edition 5.1 section 10.3都在这里做正确的事。原因与[[Configurable]]
属性属性有关,该属性在后台分配给本机和用户创建的属性。建立用户创建的属性后,此属性将设置为true
。这允许开发人员在属性上执行assign和delete命令。
var test = {};
test.me = "OK" // [[Configurable]] is true so No Problem!
delete test.me // Good here too!
要防止某些情况下不应删除或修改对象属性,默认情况下[[Configurable]]
设置为false
。哪个尊重语言规范:
如果未明确指定属性的值 命名属性的规范,表中定义的默认值 使用7 ...
[[Configurable]] false
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
本身就是真的呢?
根据语言规范(JSFiddle)确定:
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]]
答案 3 :(得分:-1)
我认为他正在寻找的答案,以及之前基本上已经说过的人,但是通过编辑添加更多解释会使得清晰度变得混乱:
当你以一种非标准的原始方式使用方法时,结果是未定义的,因此在浏览器之间会有所不同(因为每个基本上都有不同的js引擎)它的处理方式。