Javascript中的delete介绍

一、问题的提出

  我们先来看看下面几段代码,要注意的是,以下代码不要在浏览器的开发者工具(如FireBug、Chrome Developer tool)中运行,原因后面会说明:

  为什么我们可以删除对象的属性:


代码如下:

var o = { x: 1 };
delete o.x; // true
o.x; // undefined  

但不以删除像这样声明的变量:


代码如下:

var x = 1;
delete x; // false
x; // 1

也不能删除像这样定义的函数:


代码如下:

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

注意:当delete操作符返回true时表示可以删除,返回false表示不能删除

  要理解这一点,我们首先需要掌握像变量实例化和属性特性这样的概念--遗憾的是这些内容在一些javascript的书中很少讲到。理解它们并不难,如果你不在乎它们为什么这么运行,你可以随意的跳过这一部分。

二、代码类型

  在ECMAScript中有三种类型的可执行代码:Global code(全局代码)、Function code(函数代码)和 Eval code(放在Eval中执行的代码)。


代码如下:

var x=1;//Global code
function test(){
var y=2;//Function Code
eval("var z=3");//Eval Code in Function
}
eval("function evalTest(){}");//Eval Code in Global

三、执行上下文

  当ECMAScript 代码执行时,它总是在一定的上下文中运行,执行上下文是一个有点抽象的实体,它有助于我们理解作用域和变量实例化如何工作的。对于三种类型的可执行代码,每个都有执行的上下文。当一个函数执行时,可以说控制进入到函数代码(Function code)的执行上下文。全局代码执行时,进入到全局代码(Global code)的执行上下文。

  正如你所见,执行上下文逻辑上来自一个栈。首先可能是有自己作用域的全局代码,代码中可能调用一个函数,它有自己的作用域,函数可以调用另外一个函数,等等。即使函数递归地调用它自身,每一次调用都进入一个新的执行上下文。

四、Activation object(激活对象)/Variable object(变量对象)

  每一个执行上下文在其内部都有一个Variable Object。与执行上下文类似,Variable object是一个抽象的实体,用来描述变量实例化的机制。有趣的是在代码中声明的变量和函数实际上被当作这个变量对象的属性被添加。

  当进入全局代码的执行上下文时,一个全局对象用作变量对象。这也正是为什么在全局范围中声明的变量或者函数变成了全局对象的属性。


代码如下:

/* remember that `this` refers to global object when in global scope */
var GLOBAL_OBJECT = this;

var foo = 1;
GLOBAL_OBJECT.foo; // 1
foo === GLOBAL_OBJECT.foo; // true

function bar(){}
typeof GLOBAL_OBJECT.bar; // "function"
GLOBAL_OBJECT.bar === bar; // true

全局变量变成了全局对象的属性,但是,那些在函数代码(Function code)中定义的局部变量又会如何呢?行为其实很相似:它成了变量对象的属性。唯一的差别在于在函数代码(Function code)中,变量对象不是全局对象,而是所谓的激活对象(Activation object)。每次函数代码(Function code)进入执行作用域时,就会创建一个激活对象(Activation object)。

  不仅函数代码(Function code)中的变量和函数成为激活对象的属性,而且函数的每一个参数(与形参相对应的名称)和一个特定Arguments 对象也是。注意,激活对象是一种内部机制,不会被程序代码真正访问到。


代码如下:

(function(foo){

var bar = 2;
function baz(){}

/*
In abstract terms,

Special `arguments` object becomes a property of containing function's Activation object:
ACTIVATION_OBJECT.arguments; // Arguments object

...as well as argument `foo`:
ACTIVATION_OBJECT.foo; // 1

...as well as variable `bar`:
ACTIVATION_OBJECT.bar; // 2

...as well as function declared locally:
typeof ACTIVATION_OBJECT.baz; // "function"
*/

})(1);

最后,在Eval 代码(Eval code)中声明的变量作为正在调用的上下文的变量对象的属性被创建。Eval 代码(Eval code)只使用它正在被调用的哪个执行上下文的变量对象。


代码如下:

var GLOBAL_OBJECT = this;

/* `foo` is created as a property of calling context Variable object,
which in this case is a Global object */

eval('var foo = 1;');
GLOBAL_OBJECT.foo; // 1

(function(){

/* `bar` is created as a property of calling context Variable object,
which in this case is an Activation object of containing function */

eval('var bar = 1;');

/*
In abstract terms,
ACTIVATION_OBJECT.bar; // 1
*/

})();

五、属性特性
  现在变量会怎样已经很清楚(它们成为属性),剩下唯一的需要理解的概念是属性特性。每个属性都有来自下列一组属性中的零个或多个特性--ReadOnly, DontEnum, DontDelete 和Internal,你可以认为它们是一个标记,一个属性可有可无的特性。为了今天讨论的目的,我们只关心DontDelete 特性。

  当声明的变量和函数成为一个变量对象的属性时--要么是激活对象(Function code),要么是全局对象(Global code),这些创建的属性带有DontDelete 特性。但是,任何明确的(或隐含的)创建的属性不具有DontDelete 特性。这就是我们为什么一些属性能删除,一些不能。


代码如下:

var GLOBAL_OBJECT = this;

/* `foo` is a property of a Global object.
It is created via variable declaration and so has DontDelete attribute.
This is why it can not be deleted. */

var foo = 1;
delete foo; // false
typeof foo; // "number"

/* `bar` is a property of a Global object.
It is created via function declaration and so has DontDelete attribute.
This is why it can not be deleted either. */

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

/* `baz` is also a property of a Global object.
However, it is created via property assignment and so has no DontDelete attribute.
This is why it can be deleted. */

GLOBAL_OBJECT.baz = 'blah';
delete GLOBAL_OBJECT.baz; // true
typeof GLOBAL_OBJECT.baz; // "undefined"

六、内置属性和DontDelete

  一句话:属性中一个独特的特性(DontDelete)控制着这个属性是否能被删除。注意,对象的内置属性(即对象的预定义属性)有DontDelete 特性,因此不能被删除。特定的Arguments 变量(或者,正如我们现在了解的,激活对象的属性),任何函数实例的length属性也拥有DontDelete 特性。


代码如下:

(function(){

/* can't delete `arguments`, since it has DontDelete */

delete arguments; // false
typeof arguments; // "object"

/* can't delete function's `length`; it also has DontDelete */

function f(){}
delete f.length; // false
typeof f.length; // "number"

})();

与函数参数相对应的创建的属性也有DontDelete 特性,因此也不能被删除。


代码如下:

(function(foo, bar){

delete foo; // false
foo; // 1

delete bar; // false
bar; // 'blah'

})(1, 'blah');

七、未声明的赋值

  简单地就是未声明的赋值在一个全局对象上创建一个可删除的属性。


代码如下:

var GLOBAL_OBJECT = this;

/* create global property via variable declaration; property has DontDelete */
var foo = 1;

/* create global property via undeclared assignment; property has no DontDelete */
bar = 2;//可理解为 window.bar=2; 根据上面的第五点是可以删除的

delete foo; // false
typeof foo; // "number"

delete bar; // true
typeof bar; // "undefined"

请注意,DontDelete特性是在属性创建的过程中确定的,后来的赋值不会修改现有属性已经存在的特性,理解这一点很重要。


代码如下:

/* `foo` is created as a property with DontDelete */
function foo(){}

/* Later assignments do not modify attributes. DontDelete is still there! */
foo = 1;
delete foo; // false
typeof foo; // "number"

/* But assigning to a property that doesn't exist,
creates that property with empty attributes (and so without DontDelete) */

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

八、Eval code
  在Eval中创建的变量或方法比较特别,没有DontDelete特性,也就是说可以删除。

代码如下:

eval("var x = 1;");
console.log(x); // 1
delete x;
console.log(typeof x); // undefined

eval("function test(){ var x=1; console.log(delete x);/* false */;return 1;}");
console.log(test()); // 1
delete test;
console.log(typeof test); // undefined  

注意,这里说的在Eval中创建的变量或方法不包括方法内部的变量或方法,如上面代码中的红色部分,仍然跟之前讲的一致:不能被删除。

九、FireBug的困惑

  我们看一段在FireBug中执行的代码结果:


代码如下:

var x=1;
delete x;
console.log(typeof x);//undefined

function y(){
var z=1;
console.log(delete z);//false
}
y();
delete y;
console.log(typeof y);//undefined

这明明是违反上述规则的,但跟上面第八点对比后发现,这正在代码在eval中执行的效果。虽然没有证实,但我猜测FireBug(Chrome Developer tool)中控制台代码是用eval执行的。

所以,当大家在测试JS代码时,如果涉及到当前上下文环境时特别要注意。

十、delete操作符删除的对象

  C++中也有delete操作符,它删除的是指针所指向的对象。例如:

代码如下:

class Object {
public:
Object *x;
}

Object o;
o.x = new Object();
delete o.x; // 上一行new的Object对象将被释放

但Javascript的delete与C++不同,它不会删除o.x指向的对象,而是删除o.x属性本身。


代码如下:

var o = {};
o.x = new Object();
delete o.x; // 上一行new的Object对象依然存在
o.x; // undefined,o的名为x的属性被删除了 

 在实际的Javascript中,delete o.x之后,Object对象会由于失去了引用而被垃圾回收, 所以delete o.x也就“相当于”删除了o.x所指向的对象,但这个动作并不是ECMAScript标准, 也就是说,即使某个实现完全不删除Object对象,也不算是违反ECMAScript标准。

  “删除属性而不是删除对象”这一点,可以通过以下的代码来确认。


代码如下:

var o = {};
var a = { x: 10 };
o.a = a;
delete o.a; // o.a属性被删除
o.a; // undefined
a.x; // 10, 因为{ x: 10 } 对象依然被 a 引用,所以不会被回收

另外,delete o.x 也可以写作 delete o["x"],两者效果相同。

十一、其他不能被删除的属性

  除了上面说过的内置属性(即预定义属性)不能被删除外,prototype中声明的属性也不能delete:


代码如下:

function C() { this.x = 42; }
C.prototype.x = 12;
C.prototype.y = 13;

var o = new C();
o.x; // 42, 构造函数中定义的o.x

delete o.x; //true 删除的是自身定义的x
o.x; // 12, prototype中定义的o.x,即使再次执行delete o.x也不会被删除

delete o.y; //true,因为 o自身没有o.y属性,y存在于prototype链中,也就是说对象自身属性和prototype属性是不同的
o.y; //13

小结

  上面说了那么多,希望对大家认识JavaScript中的Delete有所帮助。由于水平有限,不保证完全正确,如果发现错误欢迎指正。

原文为:
  1、http://perfectionkills.com/understanding-delete/(英文)
  2、http://nanto.asablo.jp/blog/2008/01/09/2552470(日文)

本文首发http://jscode.cnblogs.com

(0)

相关推荐

  • JavaScript从数组中删除指定值元素的方法

    本文实例讲述了JavaScript从数组中删除指定值元素的方法.分享给大家供大家参考.具体分析如下: 下面的代码使用了两种方式删除数组的元素,第一种定义一个单独的函数,第二种为Array对象定义了一个removeByValue的方法,调用非常简单 定义函数removeByValue进行元素删除 function removeByValue(arr, val) { for(var i=0; i<arr.length; i++) { if(arr[i] == val) { arr.splice(i,

  • javascript中删除指定数组中指定的元素的代码

    函数如下: 复制代码 代码如下: foreach = function (obj, insp){ if(obj== null && obj.constructor != Array){ return []; } //obj是要处理的数组,obj==null 表示对象尚未存在:obj.constructor != Array 表示对象obj的属性的构造函数不是数组: //constructor属性始终指向创建当前对象的构造函数.两个条件均满足,则返回空数组[]: //下面对construct

  • Javascript根据指定下标或对象删除数组元素

    将一下代码放在全局js文件中: Js代码 复制代码 代码如下: /** *删除数组指定下标或指定对象 */ Array.prototype.remove=function(obj){ for(var i =0;i <this.length;i++){ var temp = this[i]; if(!isNaN(obj)){ temp=i; } if(temp == obj){ for(var j = i;j <this.length;j++){ this[j]=this[j+1]; } thi

  • 基于JavaScript实现移除(删除)数组中指定元素

    在Array对象中有给定的函数可以删除数组中指定的元素,虽然非常好用,但是总感觉看不到摸不着的比较别扭,下面就分享一个自定义的删除数组指定索引值元素的函数,希望给大家一个全新的思路. 代码实例如下: var array=[]; array[0]="我们一"; array[1]="我们二"; array[2]="我们三"; array[3]="我们四"; array[4]="我们五"; function re

  • JavaScript delete 属性的使用

    delete 是删除对象的一个属性,例如对于一个对象, var obj = {key:5}; delete obj.key就是删除该对象的key属性,这个没什么问题,但当对象的原型prototype对象也存在该属性时,就值得注意了. 复制代码 代码如下: var A = function(){}; A.prototype.testMe = true; var a = new A(); //覆盖原型属性 a.testMe = true; if(a.testMe){ // 一些关键代码... //

  • JavaScript中诡异的delete操作符

    delete这个操作符呢,在javascript中不是很常用,但是他的特性的确很诡异. 1,删除对象的属性,代码: 复制代码 代码如下: var o = {     a: 1,     b: 2   }; delete o.a; alert(o.a);  //undefined 那么到底delete删除的是对象的属性还是对象的属性值呢,我开始觉得删除的应该是值,因为结果是undefined,而没有报错.但是事实上,我的看法是错误的,举例说明: 复制代码 代码如下: var o = {}; var

  • js删除数组元素、清空数组的简单方法(必看)

    一.清空数组 var ary = [1,2,3,4]; ary.splice(0,ary.length);//清空数组 console.log(ary); // 输出 [],空数组,即被清空了 二.删除数组元素 var ary = [1,2,3,4]; ary.splice(0,1); 或 ary.splice($.inArray(2, ary), 1); 其中$.inArray(2, ary)用来查找某元素在数组中的索引位置. 三,js 删除数组几种方法 var arr=['a','b','c

  • js delete 用法(删除对象属性及变量)

    1,对象属性删除 function fun(){ this.name = 'mm'; } var obj = new fun(); console.log(obj.name);//mm delete obj.name; console.log(obj.name); //undefined 2,变量删除 var name = 'lily'; delete name; console.log(name); //lily 直接用delelte删除不了变量 3,删除不了原型链中的变量 fun.proto

  • js 删除数组的几种方法小结

    var arr=['a','b','c']; 若要删除其中的'b',有两种方法: 1.delete方法:delete arr[1] 这种方式数组长度不变,此时arr[1]变为undefined了,但是也有好处原来数组的索引也保持不变,此时要遍历数组元素可以才用 for(index in arr) { document.write('arr['+index+']='+arr[index]); } 这种遍历方式跳过其中undefined的元素 * 该方式IE4.o以后都支持了 2.数组对象splic

  • js删除Array数组中指定元素的两种方法

    本节内容: js删除Array数组中指定元素 方法一, /* * 方法:Array.remove(dx) 通过遍历,重构数组 * 功能:删除数组元素. * 参数:dx删除元素的下标. */ Array.prototype.remove=function(dx) { if(isNaN(dx)||dx>this.length){return false;} for(var i=0,n=0;i<this.length;i++) { if(this[i]!=this[dx]) { this[n++]=

  • javascript delete 使用示例代码

    javascript delete example 复制代码 代码如下: var flower={}; flower.name="oop"; delete flower.name; //true alert(flower.name); //undefined 创建一个名为flower的对象 flower具有成员name,值"oop"; delete 操作 删除这个成员 删除成功,已不存在flower.name这个成员 javascript delete exampl

  • Javascript remove 自定义数组删除方法

    复制代码 代码如下: <html xmlns="http://www.w3.org/1999/xhtml" > <head> <title>Javascript自定义数组删除方法remove()</title> <script type="text/javascript"> Array.prototype.remove=function(dx){ if(isNaN(dx)||dx>this.lengt

  • JavaScript使用delete删除数组元素用法示例【数组长度不变】

    本文实例讲述了JavaScript使用delete删除数组用法.分享给大家供大家参考,具体如下: javascript使用delete删除数组中的某些数值后,数组的长度是不变的. 具体代码如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>JavaScript delete</title> </

随机推荐