之前对delete操作符理解不深太深,碰到有些问题发现自己居然自己理解不了,经过寻师访友之后发现原来是自己基础知识不够扎实,所以各位少年还是得多多修行,才能处事不惊啊!
好了进入主题,首先看个例子:
1 //例一 2 var o = { x: 1 }; 3 delete o.x; // true 4 o.x; // undefined 5 6 //例二 7 var x = 1; 8 delete x; // false 9 x; // 1 10 11 //例三 12 function x(){} 13 delete x; // false 14 typeof x; // "function"
从上面的三个例子中可以看出delete操作符不能删除通过var声明的变量,也不能删除函数,但是可以删除显示声明的对象的属性。这是为什么呢?对于例一大家应该很容易理解,对于例子二、三
大家则需要理解一些javascript中的概念。来看看下面这几个概念:
1、代码类型
在ECMAScript中有三种类型的可执行代码:Global code(全局代码)、Function code(函数代码)和 Eval code(放在Eval中执行的代码)
1 var x=1;//Global code 2 function test(){ 3 var y=2;//Function Code 4 eval("var z=3");//Eval Code in Function 5 } 6 eval("function evalTest(){}");//Eval Code in Global
2、执行上下文
当javascript代码执行时,它总是在一定的上下文中运行,执行上下文是一个有点抽象的实体,它有助于我们理解作用域和变量实例化如何工作的。对于三种类型的可执行代码,每个都有执行的上下文。
当一个函数执行时,可以说控制进入到函数代码(Function code)的执行上下文。全局代码执行时,进入到全局代码(Global code)的执行上下文。执行上下文逻辑上来自一个栈。首先可能是有自己作用
域的全局代码,代码中可能调用一个函数,它有自己的作用域,函数可以调用另外一个函数,等等。即使函数递归地调用它自身,每一次调用都进入一个新的执行上下文。
3、Activation object(激活对象)/Variable object(变量对象)
每一个执行上下文在其内部都有一个Variable Object(变量对象)。与执行上下文类似,Variable object是一个抽象的实体,用来描述变量实例化的机制。有趣的是在代码中声明的变量和函数实际上被当作
这个变量对象的属性被添加。当进入全局代码的执行上下文时,一个全局对象用作变量对象。这也正是为什么在全局范围中声明的变量或者函数变成了全局对象的属性。
全局变量变成了全局对象的属性,但是,那些在函数代码(Function code)中定义的局部变量又会如何呢?行为其实很相似:它成了变量对象的属性。唯一的差别在于在函数代码(Function code)中,
变量对象不是全局对象,而是所谓的激活对象(Activation object)。每次函数代码(Function code)进入执行作用域时,就会创建一个激活对象(Activation object)。
不仅函数代码(Function code)中的变量和函数成为激活对象的属性,而且函数的每一个参数(与形参相对应的名称)和一个特定Arguments 对象也是。注意,激活对象是一种内部机制,不会被程序代码真正访问到。
4、属性特性
现在变量会怎样已经很清楚(它们成为属性),剩下唯一的需要理解的概念是属性特性。每个属性都有来自下列一组属性中的零个或多个特性--ReadOnly, DontEnum, DontDelete 和Internal,你可以认
为它们是一个标记,一个属性可有可无的特性。现在我们只讨论DontDelete 特性。
当声明的变量和函数成为一个变量对象的属性时--要么是激活对象(Function code),要么是全局对象(Global code),这些创建的属性带有DontDelete 特性。但是,任何明确的(或隐含的)创建的属
性不具有DontDelete 特性。这就是我们为什么一些属性能删除,一些不能。
5、内置属性和DonDelete
属性中一个独特的特性(DontDelete)控制着这个属性是否能被删除。注意,对象的内置属性(即对象的预定义属性)有DontDelete 特性,因此不能被删除。特定的Arguments 变量(或者,正如我们现在了解
的,激活对象的属性),任何函数实例的length属性也拥有DontDelete 特性。与函数参数相对应的创建的属性也有DontDelete 特性,因此也不能被删除。未声明的赋值在一个全局对象上创建一个可删除的属性。
1 (function(foo, bar){ 2 3 delete foo; // false 4 foo; // 1 5 6 delete bar; // false 7 bar; // 'blah' 8 9 })(1, 'blah');
6、eval code
在Eval中创建的变量或方法比较特别,没有DontDelete特性,也就是说可以删除。
1 eval("var x = 1;"); 2 console.log(x); // 1 3 delete x; 4 console.log(typeof x); // undefined 5 6 eval("function test(){ var x=1; console.log(delete x);/* false */;return 1;}"); 7 console.log(test()); // 1 8 delete test; 9 console.log(typeof test); // undefined;注意在chrome的控制台执行此行代码时test没有被删除typeof test为function,在浏览器中运行test确实被删除了
注意,这里说的在Eval中创建的变量或方法不包括方法内部的变量或方法,如上面代码中test函数中的局部变量x,仍然跟之前讲的一致,不能被删除。
另外说明一个知识点:
在实际的Javascript中,delete o.a删除的是o.a属性本身,而不是删除o.a指向的对象,如下例子可以证明。
1 var o = {}; 2 var a = { x: 10 }; 3 o.a = a; 4 delete o.a; // o.a属性被删除 5 o.a; // undefined 6 a.x; // 10, 因为{ x: 10 } 对象依然被 a 引用,所以不会被回收
函数的原型属性也不能被删除:
1 function C() { this.x = 42; } 2 C.prototype.x = 12; 3 4 var o = new C(); 5 o.x; // 42, 构造函数中定义的o.x 6 7 delete o.x; //true 删除的是自身定义的x 8 o.x; // 12, prototype中定义的o.x,即使再次执行delete o.x也不会被删除