简体   繁体   English

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

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

I was planning on using the delete operator in JavaScript for something, when I decided to remind myself how it worked by playing with it some. 我计划在JavaScript中使用delete运算符,当我决定通过使用它来提醒自己它是如何工作的时候。 I understand that "delete" is supposed to be used on object properties, but I wanted to see how it behaves on variables. 我理解“删除”应该用于对象属性,但我想看看它在变量上的行为方式。 However, some weird results occurred when I put the following snippet of code in different browsers: 但是,当我将以下代码片段放在不同的浏览器中时,会出现一些奇怪的结果:

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

In Safari, the JavaScript console printed out the error "ReferenceError: Can't find variable: one". 在Safari中,JavaScript控制台打印出错误“ReferenceError:找不到变量:一个”。 Firefox gave a similar response: "ReferenceError: one is not defined". Firefox给出了类似的回应:“ReferenceError:一个未定义”。 However, Chrome printed out the value of the variable, 1. Can anyone explain why Chrome behaves differently than Safari and Firefox in this regard? 但是,Chrome打印出变量的值,1。有人可以解释为什么Chrome在这方面的行为与Safari和Firefox不同吗?

Don't trust the console . 不要相信控制台 Some codes behave different there. 有些代码表现不同。

The following will alert 1 if you run it on a real page: 如果您在真实页面上运行它,以下将提醒1:

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

Demo 演示

(Tested on Firefox, Chrome, IE, Safari and Opera.) (在Firefox,Chrome,IE,Safari和Opera上测试过。)


Understanding delete explains why the console (or firebug) shows a different behavior: 理解删除解释了控制台(或firebug)显示不同行为的原因:

Every execution context has a so-called Variable Object associated with it. 每个执行上下文都有一个与之关联的所谓变量对象 Similarly to execution context, Variable object is an abstract entity, a mechanism to describe variable instantiation. 与执行上下文类似,Variable对象是一个抽象实体,一种描述变量实例化的机制。 Now, the interesing part is that variables and functions declared in a source text are actually added as properties of this Variable object . 现在,有趣的部分是在源文本中声明的变量和函数实际上被添加为此Variable对象的属性

Finally, variables declared within Eval code are created as properties of calling context's Variable object . 最后,在Eval代码中声明的变量被创建为调用上下文的Variable对象的属性

When declared variables and functions become properties of a Variable object — either Activation object (for Function code), or Global object (for Global code), these properties are created with DontDelete attribute . 当声明的变量和函数成为Variable对象的属性 - Activation对象(对于Function代码)或Global对象(对于Global代码)时,这些属性是使用DontDelete属性创建的 However, any explicit (or implicit) property assignment creates property without DontDelete attribute . 但是,任何显式(或隐式)属性赋值都会创建没有DontDelete属性的属性 And this is essentialy why we can delete some properties, but not others. 这就是为什么我们可以删除一些属性,而不是其他属性。

So what happens in Firebug? 那么Firebug会发生什么? Why is it that variables declared in console can be deleted, contrary to what we have just learned? 为什么在控制台中声明的变量可以被删除,这与我们刚刚学到的相反? Well, as I said before, Eval code has a special behavior when it comes to variable declaration. 好吧,正如我之前所说的,Eval代码在变量声明方面有一个特殊的行为。 Variables declared within Eval code are actually created as properties without DontDelete . 在Eval代码中声明的变量实际上是作为没有DontDelete的属性创建的

Let's checkout the docs on delete from MDN. 让我们查看从MDN delete的文档。

The delete operator removes a property from an object. delete运算符从对象中删除属性。

You are using it a way that doesn't make much sense, that is to remove a local variable. 您正在以一种没有多大意义的方式使用它,即删除局部变量。

Those docs also say: 那些文档还说:

Throws in strict mode if the property is an own non-configurable property (returns false in non-strict). 如果属性是自己的不可配置属性,则以严格模式抛出(在非严格中返回false)。 Returns true in all other cases. 在所有其他情况下返回true。

Which means your usage here would throw an exception in strict mode, since you are using delete in an unsupported way. 这意味着您在此处的使用会在严格模式下抛出异常,因为您以不受支持的方式使用delete This is proven when you do: 当你这样做时,这证明了:

var one = 1;
delete one; // returns false

And as the docs mention, a return value of false means the delete operation did not succeed. 正如文档所提到的,返回值为false意味着delete操作没有成功。


If you use it properly, it should behave like you expect: 如果你正确使用它,它应该像你期望的那样:

var obj = {one: 1};
delete obj.one;    // returns true
alert(obj.one);    // alerts "undefined"

Revised Answer: 修订答案:

Based on feedback from @Oriol concerning property attributes. 基于@Oriol关于属性属性的反馈。 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 ) 我发现这里的真正问题是属性属性 (参见ECMA-262版本5.1节8.6.1 )和变量环境的执行上下文(参见ECMA-262版本5.1第10.3节

Can anyone explain why Chrome behaves differently than Safari and Firefox in this regard? 任何人都可以解释为什么Chrome在这方面与Safari和Firefox的行为不同?

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

Two things are happening here: 这里发生了两件事:

  1. The var declaration binds the declared object into an "Execution context" that is distinctly different from the Global ( window ) one. var声明将声明的对象绑定到一个“执行上下文”,它与Global( window )明显不同。
  2. JavaScript evaluates the [[Configurable]] property to determine if its "OK" to delete JavaScript评估[[Configurable]]属性以确定是否删除“OK”

Concerning #1 关于#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. 代码中的var声明建立了一个VariableEnvironment ,从而将值绑定到与全局变量完全不同的执行上下文(范围)中的对象。 So naturally, when var is not used the VariableEnvironment is interpreted in a global execution binding process, making statements like one = 1; 很自然地,当不使用var时, VariableEnvironment在全局执行绑定过程中被解释,使得语句像one = 1; or delete one; 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 10.4建立执行上下文

Evaluation of global code or code using the eval function (15.1.2.1) establishes and enters a new execution context... 使用eval函数(15.1.2.1)评估全局代码或代码建立并输入新的执行上下文...

10.4.2 Entering Eval Code 10.4.2输入Eval代码

The following steps are performed when control enters the execution context for eval code: 当控件进入eval代码的执行上下文时,执行以下步骤:

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

Concerning #2 关于#2

Chrome and JSFiddle are both doing the right thing here. Chrome和JSFiddle都在这里做正确的事情。 The the reason has to do with the [[Configurable]] property attribute, which is assigned to both native and user-created properties behind the scenes. 原因与[[Configurable]]属性属性有关,该属性在后台分配给本机和用户创建的属性。 When a user-created property is established, this attribute is set to true . 建立用户创建的属性时,此属性设置为true This allows the developer to execute assign and delete commands on the property. 这允许开发人员在属性上执行assign和delete命令。

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. 要防止某些情况下不应删除或修改对象属性[[Configurable]]默认情况下[[Configurable]]设置为false 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... 如果此规范没有为命名属性显式指定属性的值,则使用表7中定义的默认值...

[[Configurable]] false [[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. 由此我们可以理解Firefox和Safari不会遵守规则。 When var one=1; 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 . 在这些浏览器的控制台中声明,默认情况下,此范围内的属性被错误地视为[[Configurable]] ,因此删除var one而不是隐含的window.one

In Firefox/Safari: 在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? “好的等等!那么为什么要delete one真的呢?

It plays out as determined by the language spec ( 10.4.2 ): 根据语言规范( 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]]

I think the answer he's looking for, and someone essentially said earlier, but muddied up the clarity by adding more explanation through an edit should be restated thus: 我认为他正在寻找的答案,以及之前基本上已经说过的人,但是通过编辑添加更多解释,应该重申清晰度:

When you use a method in a way that was not original dictated in the standard, then the result is undefined and therefore varies from browser to browser ( because each essentially has a different js engine ) in the way that it's handled. 当你以一种非标准的原始方式使用方法时,结果是未定义的,因此在浏览器之间会有所不同( 因为每个浏览器基本上都有不同的js引擎 )。

暂无
暂无

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

相关问题 为什么&#39;&lt;&lt;&#39;运算符在Javascript和PHP中的行为有时会有所不同? - Why does the '<<' operator sometimes behave differently in Javascript and PHP? 为什么&#39;+&#39;运算符在JavaScript中的行为不同于&#39;*&#39;,&#39;/&#39;和&#39;-&#39;运算符 - Why does the '+' operator behave different from '*' ,'/' and '-' operator in javascript JavaScript删除对象在不同的​​浏览器中的行为有所不同 - JavaScript delete objects behaves differently in different browsers 为什么jQuery的行为与javascript不同? - Why does jQuery behave differently than javascript? 为什么/ * * /注释的行为不同? Javascript错误? - Why does /* */ comment behave differently ? Javascript bug? 为什么 || JavaScript 中的 (or) 和 &amp;&amp; (and) 运算符的行为与 C 中的不同(返回非布尔值)? - Why does the || (or) and && (and) operator in JavaScript behave differently than in C (returning non boolean value)? 为什么这个画布在不同浏览器中的反应不同 - Why does this canvas react differently in different browsers 为什么 oninput 事件在 Angular 中的行为与在 JavaScript 中的行为不同? - Why does the oninput event behave differently in Angular than it does in JavaScript? 为什么此全局Javascript变量在函数内部和外部的行为有所不同? - Why does this global Javascript variable behave differently inside and outside of a function? 为什么这个javascript对象在有和没有模块模式的情况下表现不同? - Why does this javascript object behave differently with and without a module pattern?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM