javascript中的delete使用详解(4)

函数声明不止替换了属性的值,同时也替换了它的内部属性。 如果我们通过 eval 来声明函数,这一函数也将用它自己的内部属性来替换之前的。 而由于在 eval 中声明的变量生成的属性没有 DontDelete, 实例化这个函数将在“理论上”移除原属性已有的 DontDelete 内部属性, 而使得这一属性可以删除(当然,同时也将值指向了新生成的函数)。

复制代码 代码如下:


var x = 1;
/*不能删除,‘x'拥有DontDelete*/
delete x; // false
typeof x; // "number"

eval('function x() { }');
/* 属性'x'现在指向函数,并且应该没有DontDelete */
typeof x; // "function"
delete x; // 应该是‘true';
typeof x; // 应该是"undefined"

不幸的是,这种欺骗技术在我尝试的各个浏览器中都没有成功。 这里我可能错过了什么,或者这个行为太隐蔽而以至于各个浏览器没有注意到它。

(译者按:这里的问题可能在于:函数声明和变量声明之间的覆盖只是值指向的改变, 而内部属性 DontDelete 则在最初声明处确定而不再改变,而 eval 中声明的变量和函数,也只是在其外部上下文中未声明过的那部分才能被删除。 关于执行顺序,由于 eval 作为函数,它的调用永远在其外部上下文中其他变量和函数声明之后, 因此相关的内部属性也已确定,覆盖的只是值的指向。如下:)

复制代码 代码如下:


/*  第一个 alert 返回 “undefined”,因为赋值过程在声明过程和eval执行过程之后;
    第二个alert返回 “false”, 因为尽管x声明的位置在eval之后,
    但是eval的执行却在变量声明之后,因此已无法删除 */
eval(' alert( x ); alert(delete x) ');
var x = 1;

三、浏览器的遵守情况 | Browsers compliance

了解事物的工作原理是重要的,但实际的实现情况更重要。 浏览器在创建和删除变量/属性时都遵守这些标准吗? 对于大部分来说,是的。

我写了一个简单的测试单元来检查全局代码、函数代码和Eval代码的遵守情况。 测试单元同时检测了 delete 操作的返回值和属性是否像预期那样被删除。 delete 的返回值并不像它的实际结果那样重要,delete 操作返回 true 或 false 并不重要, 重要的是拥有/没有 DontDelete 的属性是否被删除。

现代浏览器总的来说还是遵守删除规则的,以下浏览器全部通过测试: Opera 7.54+, Firefox 1.0+, Safari 3.1.2+, Chrome 4+。

Safari 2.x 和 3.0.4 在删除函数 arguments 时存在问题,似乎这些属性在创建时不带 DontDelete,因此可以被删除。 Safari 2.x 还有其他问题——删除无引用时(例如delete 1)抛出错误(译者按:IE 同样有); 函数声明生成了可删除的属性(奇怪的是变量声明则正常); eval 中的变量声明变成不可删除(而 eval 中的函数声明则正常)。

与 Safari 类似,Konqueror(3.5,而非4.3)在 delete 无引用和删除 arguments 是也存在同样问题。

3.1、Gecko DontDelete bug
Gecko 1.8.x 浏览器—— Firefox 2.x, Camino 1.x, Seamonkey 1.x, etc. ——存在一个有趣的 bug:显式赋值值给一个属性能移除它的 DontDelete,即使该属性通过变量或函数声明而生成。

复制代码 代码如下:


function foo() { };
delete foo; // false;
typeof foo; // "function"

this.foo = 1;
delete foo; // true
typeof foo; // "undefined"

令人惊讶的是,IE5.5-8 也通过了绝大部分测试,除了删除非引用抛出错误(e.g. delete 1,就像旧的 Safari)。 但是,虽然不能马上发现,事实上 IE 存在更严重的 bug,这些 bug 是关于全局对象。

四、IE bugs

在 IE 中(至少在 IE6-8 中),下面的表达式抛出异常(在全局代码中):

复制代码 代码如下:


this.x = 1;
delete x; // TypeError: Object doesn't support this action

而下面则是另一个:

复制代码 代码如下:


var x =1;
delete this.x; // TypeError: Cannot delete 'this.x'
// 译者按:在IE8下抛出此异常,在IE6,7下抛出的是和上面一样的异常

这似乎说明,在 IE 中在全局代码中的变量声明并没有生成全局对象的同名属性。 通过赋值创建的属性(this.x = 1)然后通过 delete x 删除时抛出异常; 通过变量声明(var x = 1)创建的属性然后通过 delete this.x 删除时抛出另一个(译者按:在 IE6,7 下错误信息与上面的相同)。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wdgsjx.html