但不只是这样,事实上通过显式赋值创建的属性在删除时总是抛出异常。 这不只是一个错误,而是创建的属性看上去拥有了 DontDelete 内部属性,而按规则应该是没有的:
复制代码 代码如下:
this.x = 1;
delete this.x; // TypeError: Object doesn't support this action
delete x; // TypeError: Object doesn't support this action
另一方面,未声明的变量赋值(那些同样生成全局对象的属性)又确实在IE下能够正常删除:
复制代码 代码如下:
x = 1;
delete x; // true
但如果你试图通过 this 关键字来进行删除(delete this.x),那么上面的异常又将抛出:
复制代码 代码如下:
x = 1;
delete this.x; //TypeError: Cannot delete 'this.x'
如果归纳一下,我们将发现在全局代码中‘delete this.x'永远不会成功。 当通过显式赋值来生成属性(this.x = 1)时抛出一个异常; 当通过声明/非声明变量的方式(var x = 1 or x = 1)生成属性时抛出另一个异常。 而另一方面,delete x 只有在显示赋值生成属性(this.x = 1)时才抛出异常。
在 ,其中 Garrett Smith 认为在 IE 中全局变量对象(Global variable object)实现为一个 JScript 对象,而全局对象则由宿主对象实现。
我们能通过几个测试来在某种程度上确认这一理论。 注意,this 和 window 似乎引用同一个对象(如果 ‘==='运算符可以信任的话), 而变量对象 Variable object (函数声明的基础)则与 this 引用的不同。
复制代码 代码如下:
function getBase() { return this; };
getBase() === this.getBase(); // false
this.getBase() === this.getBase(); // true
window.getBase() === this.getBase(); // true
window.getBase() === getBase(); // false
五、误解 | Misconceptions
我们不能低估理解事物工作原理的重要性。 我看过网络上一些关于 delete 操作的误解。 例如,(而且等级还很高),里面解释说“delete is supposed to be no-op when target isn't an object property”。 现在我们了解了 delete 操作的核心,也就清楚了这个答案是不正确的。 delete 不区分变量和属性(事实上在 delete 操作中这些都是引用),而只关心 DontDelete(以及属性是否已经存在)。
六、'delete'和宿主对象 | 'delete‘ and host object
一个 delete 的算法大致像这样:
1. 如果运算元(operand)不是引用,返回 true
2. 如果对象没有同名的**直接属性**,返回 true (如我们所知,对象可以是全局对象也可以是活化对象)
3. 如果属性已经存在但有 DontDelete,返回 false
4. 否则,删除移除属性并返回 true
然而,对于宿主对象(host object)的 delete 操作的行为却可能是不可预料的。 而事实上这并没有错:宿主对象(通过一定规则)允许实现任何操作, 例如读(内部[[Get]]方法)、写(内部[[Write]]方法)、删除(内部[[Delete]]方法),等等。 这种允许自定义[[Delete]]行为导致了宿主对象的混乱。
我们已经看到了在IE中的一些问题:当删除某些对象(那些实现为了宿主对象)属性时抛出异常。 一些版本的 firefox 当试图删除 window.location 时抛出异常(译者按:IE 同样抛出)。 同样,在一些宿主对象中你也不能相信 delete 的返回值, 例如下面发生在 firefox 中的(译者按:chrome 中同样结果;IE 中抛出异常;opera 和 safari 允许删除,并且删除后无法调用,姑且算'正常‘,尽管,从下面的讨论来看似乎却是不正常的,它们事实上删除了不能删除的属性,而前面的浏览器没有):
复制代码 代码如下:
/* 'alert'是'window‘的一个直接属性(如果我们能够相信'hasOwnProperty') */
window.hasOwnProperty('alert'); // true
delete window.alert; // true
typeof window.alert; // "function"
delete window.alert 返回 true,尽管这个属性没有任何条件可能产生这个结果(按照上面的算法): 它解析为一个引用,因此不能在第一步返回 true; 它是 window 对象的直接属性,因此不能在第二步返回 true; 唯一能返回 true 的是当算法达到最后一步同时确实删除这个属性,而事实上它并没有被删除。 (译者按:不,在 opera 和 safari 中确实被删除了...)。
所以这个故事告诉我们永远不要相信宿主对象。
七、ES5 严格模式 | ES5 strict mode