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

时间:2014-06-24 23:17:22

标签: javascript google-chrome

我计划在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不同吗?

4 个答案:

答案 0 :(得分:3)

不要信任控制台。有些代码在那里表现不同。

如果您在真实页面上运行,以下内容将提示1:

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

Demo

(在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?

这里发生了两件事:

  1. var声明将声明的对象绑定到"执行上下文"这与全球(window)明显不同。
  2. JavaScript评估[[Configurable]]属性以确定其是否为" OK"删除
  3. 关于#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代码   通过直接调用(15.1.2.1.1)评估到eval函数,   初始化执行上下文,就好像它是全局执行一样   上下文使用eval代码......

    关于#2

    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引擎)它的处理方式。