![](/img/trans.png)
[英]Why does the '<<' operator sometimes behave differently in Javascript and PHP?
[英]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的属性创建的 。
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?
这里发生了两件事:
var
声明将声明的对象绑定到一个“执行上下文”,它与Global( 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代码
当控件进入eval代码的执行上下文时,执行以下步骤:
如果没有调用上下文或者eval代码没有被eval函数直接调用(15.1.2.1.1)评估,则使用eval代码初始化执行上下文,就像它是一个全局执行上下文一样。 。
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.