/* 'baz'也是全局对象的一个属性,
然而,它通过属性赋值而生成,因此没有DontDelete
这就是为什么它可以被删除*/
GLOBAL_OBJECT.baz = "baz";
delete GLOBAL_OBJECT.baz; // true
typeof GLOBAL_OBJECT.baz; // "undefined"
1.5、内建和DontDelete | Build-ins and DontDelete
所以这就是所有这一切发生的原因:属性的一个特殊的内部属性控制着该属性是否可以被删除。 注意:内建对象的一些属性拥有内部属性 DontDelete,因此不能被删除; 特殊的 arguments 变量(如我们所知的,活化对象的属性)拥有 DontDelete; 任何函数实例的 length (返回形参长度)属性也拥有 DontDelete:
复制代码 代码如下:
(function() {
//不能删除'arguments',因为有DontDelete
delete arguments; // false;
typeof arguments; // "object"
//也不能删除函数的length,因为有DontDelete
function f() {};
delete f.length; // false;
typeof f.length; // "number"
}) ();
与函数 arguments 相关联的属性也拥有 DontDelete,同样不能被删除
复制代码 代码如下:
(function(foo,bar) {
delete foo; // false
foo; // 1
delete bar; // false
bar; // "bah"
}) (1,"bah");
1.6、未声明的变量赋值 | Undeclared assignments
你可能记得,未声明的变量赋值会成为全局对象的属性,除非这一属性在作用域链内的其他地方被找到。 而现在我们了解了属性赋值和变量声明的区别——后者生成 DontDelete 而前者不生成——这也就是为什么未声明的变量赋值可以被删除的原因了。
复制代码 代码如下:
var GLOBAL_OBJECT = this;
/* 通过变量声明生成全局对象的属性,拥有DontDelete */
var foo = 1;
/* 通过未声明的变量赋值生成全局对象的属性,没有DontDelete */
bar = 2;
delete foo; // false
delete bar; // true
注意:内部属性是在属性生成时确定的,之后的赋值过程不会改变已有的属性的内部属性。 理解这一区别是重要的。
/* 'foo'创建的同时生成DontDelete */
function foo() {};
/* 之后的赋值过程不改变已有属性的内部属性,DontDelete仍然存在 */
foo = 1;
delete foo; // false;
typeof foo; // "number"
/* 但赋值一个不存在的属性时,创建了一个没有内部属性的属性,因此没有DontDelete */
this.bar = 1;
delete bar; // true;
typeof bar; // "undefined"
二、Firebug 的混乱 | Firebug confusion
那么, firebug 中发生了什么? 为什么在控制台中声明的变量能够被删除,而不是想我们之前讨论的那样? 我之前说过,Eval code 在它处理变量声明时有一个特殊的行为: 在 Eval code 中声明的变量事实上生成一个没有 DontDelete 的属性。
复制代码 代码如下:
eval('var foo = 1;');
foo; // 1
delete foo; // true
typeof foo; // "undefined"
在函数代码中也是一样:
复制代码 代码如下:
(function() {
eval('var foo = 1;');
foo; // 1
delete foo; // true
typeof foo; // "undefined"
}) ();
而这就是 Firebug 中异常行为的原因了。 所有在控制台中的调试文本似乎是以 Eval code 来编译和执行的,而不是在全局或函数代码中执行。 显然,其中的变量声明最终都生成了不带 DontDelete 的属性,所以可以被删除。 所以要小心普通的全局代码和 Firebug 控制台中代码的区别。
2.1、通过eval删除变量 | Delete variables via eval
这个有趣的 eval 行为,结合 ECMAScript 的另一个方面可以在技术上允许我们删除那些原本不能删除的属性。 这个方面是关于函数声明——在相同的执行上下文中它们能覆盖同名的变量:
复制代码 代码如下:
function x() { };
var x;
typeof x; // “function”
那么为什么函数声明拥有优先权而能覆盖同名变量(或者换句话说,变量对象(Variable object)的相同属性)呢? 这是因为函数声明的实例化过程在变量声明之后,因此可以覆盖它们。
(译者按:函数声明只能覆盖声明而未赋值的同名变量,如果在声明时赋值了值(e.g. var x = 1)则赋值值的过程在函数初始化之后,函数声明反而被变量赋值所覆盖,如下:)
复制代码 代码如下:
var x = 1;
function x() { };
typeof x; // "number"