注意函数声明是如何获得优先权并且覆盖同名变量(或者, 换句话说, 在变量对象中的相同属性)的. 这是因为函数声明是在变量声明之后被实例化的, 并且被允许覆盖它们(变量声明). 函数声明不仅会替换掉一个属性的值, 它还会替换掉那个属性的特性. 如果我们通过eval来声明一个函数, 那个函数就应该会用它自己的特性来替换掉原有的(被替换的)属性的特性. 并且, 由于通过eval声明的变量会创建不带DontDelete特性的属性, 实例化这个新函数将会实际上从属性中删除已存在的DontDelete特性, 从而使得一个属性能够被删除(并且, 显然会将其值指向新创建的函数).
复制代码 代码如下:
var x = 1;
/* Can't delete, `x` has DontDelete */
delete x; // false
typeof x; // "number"
eval('function x(){}');
/* `x` property now references function, and should have no DontDelete */
typeof x; // "function"
delete x; // should be `true`
typeof x; // should be "undefined"
不幸的是, 这种"欺骗"在目前的任何实现中都不起作用. 也许我在这漏掉了什么, 或者是这种行为只是太晦涩了以至于实现者都没有注意到它.
浏览器兼容性:
在理论上了解事物是如何工作的是有用的, 但是实践却是最重要的. 当面对变量/属性的创建/删除时, 浏览器有遵循标准么? 答案是: 在大多数情况下, 是的.
我写了一个简单的测试集来测试浏览器对于delete操作符的兼容性, 包括在全局代码, 函数代码和Eval代码下的测试. 测试集检查了delete操作符的返回值和属性值是否(像它们应当表现的一样)真的被删除了. delete的返回值并不像它的真实结果一样重要. 如果delete返回true而不是false, 这其实并不重要, 重要的是那些拥有DontDelete特性的属性没有被删除,反之亦然.
现代浏览器大致上来说是相当兼容的. 除去了我之前提到的eval特点, 如下的浏览器通过了全部的测试集: Opera 7.54+, Firefox 1.0+, Safari 3.1.2+, Chrome 4+.
Safari 2.x 和 3.0.4在删除函数参数时有问题; 这些属性看起来是不带DontDelete被创建的, 所以可以删除它们. Safari 2.x有更多的问题——删除非引用类型变量(如: delete 1)会抛出异常; 函数声明会创建可删除的属性(但是, 奇怪的是, 变量声明却不会); eval中的变量声明会变成不可删除的(但是函数声明是可删除的).
跟Safari类似, Konqueror(3.5, 不是4.3)会在删除非引用类型时抛出异常(如: delete 1), 并且错误地让函数变量变为可删除的.
译者注:
我测试了最新版本的chrome和firefox以及IE, 基本还是保留在除23,24会fail其它均pass的情况. 同时测试了UC和一些手机浏览器, 除了诺基亚E72的自带浏览器还会Fail 15,16之外, 其余的自带浏览器大都与桌面浏览器效果一样. 但值得一提的是, Blackberry Curve 8310/8900的自带浏览器可以pass测试23, 令我很惊讶.
Gecko DontDelete bug:
Gecko 1.8.x 浏览器 —— Firefox 2.x, Camino 1.x, Seamonkey 1.x等等. —— 表现出了一个非常有趣的bug, 对属性的显式赋值会删除它的DontDelete特性, 即使这个属性是通过变量声明或函数声明创造的.
复制代码 代码如下:
function foo(){}
delete foo; // false (as expected)
typeof foo; // "function" (as expected)
/* now assign to a property explicitly */
this.foo = 1; // erroneously clears DontDelete attribute
delete foo; // true
typeof foo; // "undefined"
/* note that this doesn't happen when assigning property implicitly */
function bar(){}
bar = 1;
delete bar; // false
typeof bar; // "number" (although assignment replaced property)
令人吃惊的是, Internet Explorer 5.5 - 8 通过了完整的测试集, 除了删除非引用类型(如: delete 1)会抛出异常(就像旧的Safari一样). 但是在IE下有更严重的bugs, 它不是那么明显. 这些bugs跟Global object有关.
IE bugs:
这整章都在说Internet Explorer的bugs? 哇! 真是令人吃惊!
在IE中(至少是IE 6-8), 以下表达式会抛出异常(当在全局代码中执行时):
this.x = 1;
delete x; // TypeError: Object doesn't support this action
这一个也会, 但是会抛出不同的异常, 这使得事情更有趣了:
var x = 1;
delete this.x; // TypeError: Cannot delete 'this.x'
这看上去好像是在IE中, 全局代码中的变量声明没有在全局对象上创建属性. 通过赋值来创建属性(this.x = 1)和之后通过delete x来删除它会抛出错误. 通过声明来创建属性(var x = 1)并且在之后通过delete this.x来删除它会抛出另一个错误.