繁体   English   中英

为什么JavaScript“delete”运算符在不同的浏览器中表现不同?

[英]Why does the JavaScript “delete” operator behave differently in different browsers?

我计划在JavaScript中使用delete运算符,当我决定通过使用它来提醒自己它是如何工作的时候。 我理解“删除”应该用于对象属性,但我想看看它在变量上的行为方式。 但是,当我将以下代码片段放在不同的浏览器中时,会出现一些奇怪的结果:

var one = 1;
delete one;
console.log(one); // prints out 1 in Chrome, but not in Safari or Firefox

在Safari中,JavaScript控制台打印出错误“ReferenceError:找不到变量:一个”。 Firefox给出了类似的回应:“ReferenceError:一个未定义”。 但是,Chrome打印出变量的值,1。有人可以解释为什么Chrome在这方面的行为与Safari和Firefox不同吗?

不要相信控制台 有些代码表现不同。

如果您在真实页面上运行它,以下将提醒1:

var one = 1;
delete one;
alert(one);

演示

(在Firefox,Chrome,IE,Safari和Opera上测试过。)


理解删除解释了控制台(或firebug)显示不同行为的原因:

每个执行上下文都有一个与之关联的所谓变量对象 与执行上下文类似,Variable对象是一个抽象实体,一种描述变量实例化的机制。 现在,有趣的部分是在源文本中声明的变量和函数实际上被添加为此Variable对象的属性

最后,在Eval代码中声明的变量被创建为调用上下文的Variable对象的属性

当声明的变量和函数成为Variable对象的属性 - Activation对象(对于Function代码)或Global对象(对于Global代码)时,这些属性是使用DontDelete属性创建的 但是,任何显式(或隐式)属性赋值都会创建没有DontDelete属性的属性 这就是为什么我们可以删除一些属性,而不是其他属性。

那么Firebug会发生什么? 为什么在控制台中声明的变量可以被删除,这与我们刚刚学到的相反? 好吧,正如我之前所说的,Eval代码在变量声明方面有一个特殊的行为。 在Eval代码中声明的变量实际上是作为没有DontDelete的属性创建的

让我们查看从MDN delete的文档。

delete运算符从对象中删除属性。

您正在以一种没有多大意义的方式使用它,即删除局部变量。

那些文档还说:

如果属性是自己的不可配置属性,则以严格模式抛出(在非严格中返回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"

修订答案:

基于@Oriol关于属性属性的反馈。 我发现这里的真正问题是属性属性 (参见ECMA-262版本5.1节8.6.1 )和变量环境的执行上下文(参见ECMA-262版本5.1第10.3节

任何人都可以解释为什么Chrome在这方面与Safari和Firefox的行为不同?

var one = 1;
delete one;
console.log(one); // Returns 1.. but why?

这里发生了两件事:

  1. var声明将声明的对象绑定到一个“执行上下文”,它与Global( window )明显不同。
  2. JavaScript评估[[Configurable]]属性以确定是否删除“OK”

关于#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代码的执行上下文时,执行以下步骤:

如果没有调用上下文或者eval代码没有被eval函数直接调用(15.1.2.1.1)评估,则使用eval代码初始化执行上下文,就像它是一个全局执行上下文一样。 。

关于#2

Chrome和JSFiddle都在这里做正确的事情。 原因与[[Configurable]]属性属性有关,该属性在后台分配给本机和用户创建的属性。 建立用户创建的属性时,此属性设置为true 这允许开发人员在属性上执行assign和delete命令。

var test = {};
test.me = "OK" // [[Configurable]] is true so No Problem!
delete test.me // Good here too!

要防止某些情况下不应删除或修改对象属性[[Configurable]]默认情况下[[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真的呢?

根据语言规范( 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]]

我认为他正在寻找的答案,以及之前基本上已经说过的人,但是通过编辑添加更多解释,应该重申清晰度:

当你以一种非标准的原始方式使用方法时,结果是未定义的,因此在浏览器之间会有所不同( 因为每个浏览器基本上都有不同的js引擎 )。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM