一、问题的提出

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

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

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

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

  1. var x = 1;
  2. delete x; // false
  3. x; // 1

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

  1. function x(){}
  2. delete x; // false
  3. typeof x; // "function"

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

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

二、代码类型

  在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

三、执行上下文

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

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

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

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

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

  1. /* remember that `this` refers to global object when in global scope */
  2. var GLOBAL_OBJECT = this;
  3.  
  4. var foo = 1;
  5. GLOBAL_OBJECT.foo; // 1
  6. foo === GLOBAL_OBJECT.foo; // true
  7.  
  8. function bar(){}
  9. typeof GLOBAL_OBJECT.bar; // "function"
  10. GLOBAL_OBJECT.bar === bar; // true

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

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

  1. (function(foo){
  2.  
  3. var bar = 2;
  4. function baz(){}
  5.  
  6. /*
  7. In abstract terms,
  8.  
  9. Special `arguments` object becomes a property of containing function's Activation object:
  10. ACTIVATION_OBJECT.arguments; // Arguments object
  11.  
  12. ...as well as argument `foo`:
  13. ACTIVATION_OBJECT.foo; // 1
  14.  
  15. ...as well as variable `bar`:
  16. ACTIVATION_OBJECT.bar; // 2
  17.  
  18. ...as well as function declared locally:
  19. typeof ACTIVATION_OBJECT.baz; // "function"
  20. */
  21.  
  22. })(1);

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

  1. var GLOBAL_OBJECT = this;
  2.  
  3. /* `foo` is created as a property of calling context Variable object,
  4. which in this case is a Global object */
  5.  
  6. eval('var foo = 1;');
  7. GLOBAL_OBJECT.foo; // 1
  8.  
  9. (function(){
  10.  
  11. /* `bar` is created as a property of calling context Variable object,
  12. which in this case is an Activation object of containing function */
  13.  
  14. eval('var bar = 1;');
  15.  
  16. /*
  17. In abstract terms,
  18. ACTIVATION_OBJECT.bar; // 1
  19. */
  20.  
  21. })();

五、属性特性 

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

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

  1. var GLOBAL_OBJECT = this;
  2.  
  3. /* `foo` is a property of a Global object.
  4. It is created via variable declaration and so has DontDelete attribute.
  5. This is why it can not be deleted. */
  6.  
  7. var foo = 1;
  8. delete foo; // false
  9. typeof foo; // "number"
  10.  
  11. /* `bar` is a property of a Global object.
  12. It is created via function declaration and so has DontDelete attribute.
  13. This is why it can not be deleted either. */
  14.  
  15. function bar(){}
  16. delete bar; // false
  17. typeof bar; // "function"
  18.  
  19. /* `baz` is also a property of a Global object.
  20. However, it is created via property assignment and so has no DontDelete attribute.
  21. This is why it can be deleted. */
  22.  
  23. GLOBAL_OBJECT.baz = 'blah';
  24. delete GLOBAL_OBJECT.baz; // true
  25. typeof GLOBAL_OBJECT.baz; // "undefined"

六、内置属性和DontDelete 

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

  1. (function(){
  2.  
  3. /* can't delete `arguments`, since it has DontDelete */
  4.  
  5. delete arguments; // false
  6. typeof arguments; // "object"
  7.  
  8. /* can't delete function's `length`; it also has DontDelete */
  9.  
  10. function f(){}
  11. delete f.length; // false
  12. typeof f.length; // "number"
  13.  
  14. })();

与函数参数相对应的创建的属性也有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');

七、未声明的赋值

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

  1. var GLOBAL_OBJECT = this;
  2.  
  3. /* create global property via variable declaration; property has DontDelete */
  4. var foo = 1;
  5.  
  6. /* create global property via undeclared assignment; property has no DontDelete */
  7. bar = 2;//可理解为 window.bar=2; 根据上面的第五点是可以删除的
  8.  
  9. delete foo; // false
  10. typeof foo; // "number"
  11.  
  12. delete bar; // true
  13. typeof bar; // "undefined"

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

  1. /* `foo` is created as a property with DontDelete */
  2. function foo(){}
  3.  
  4. /* Later assignments do not modify attributes. DontDelete is still there! */
  5. foo = 1;
  6. delete foo; // false
  7. typeof foo; // "number"
  8.  
  9. /* But assigning to a property that doesn't exist,
  10. creates that property with empty attributes (and so without DontDelete) */
  11.  
  12. this.bar = 1;
  13. delete bar; // true
  14. typeof bar; // "undefined"

八、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 

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

九、FireBug的困惑 

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

  1. var x=1;
  2. delete x;
  3. console.log(typeof x);//undefined
  4.  
  5. function y(){
  6. var z=1;
  7. console.log(delete z);//false
  8. }
  9. y();
  10. delete y;
  11. console.log(typeof y);//undefined

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

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

十、delete操作符删除的对象

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

  1. class Object {
  2. public:
  3. Object *x;
  4. }
  5.  
  6. Object o;
  7. o.x = new Object();
  8. delete o.x; // 上一行new的Object对象将被释放

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

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

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

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

  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 引用,所以不会被回收

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

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

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

  1. function C() { this.x = 42; }
  2. C.prototype.x = 12;
  3. C.prototype.y = 13;
  4.  
  5. var o = new C();
  6. o.x; // 42, 构造函数中定义的o.x
  7.  
  8. delete o.x; //true 删除的是自身定义的x
  9. o.x; // 12, prototype中定义的o.x,即使再次执行delete o.x也不会被删除
  10.  
  11. delete o.y; //true,因为 o自身没有o.y属性,y存在于prototype链中,也就是说对象自身属性和prototype属性是不同的
  12. o.y; //13

小结

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

Javascript中的delete的更多相关文章

  1. 关于JavaScript中的delete操作

    关于JavaScript中的delete操作 看到一道题,是这样的: (function(x){ delete x; return x; })(1); 1 null undefined Error 我 ...

  2. Javascript中的delete介绍

    关于JavaScript中的Delete一直没有弄的很清楚,最近看到两篇这方面的文章,现对两文中部分内容进行翻译(内容有修改和添加,顺序不完全一致,有兴趣推荐看原文),希望能对大家有所帮助 一.问题的 ...

  3. 深入理解javascript 中的 delete(转)

    在这篇文章中作者从<JavaScript面向对象编程指南>一书中关于 delete 的错误讲起,详细讲述了关于 delete 操作的实现, 局限以及在不同浏览器和插件(这里指 firebu ...

  4. javascript 中的 delete

    那么,为什么我们能删除一个对象的属性: var x = { a: 1 }; delete x.a; // true x.a; // undefined 但却不能删除一个变量: var x = 1; d ...

  5. JS中的delete操作符

    首先,delete删除成功返回true,失败返回false. js代码: function wxCount ($element) { this.init($element); } wxCount.pr ...

  6. JavaScript中堆栈解析,已经与delete之间的关系。

    1,在栈中的数据不会随意删除. 2,堆中的数据可以随意删除. 注意:用eval("var a")定义的变量存放在栈中. var 和function 语句在JavaScript中的优 ...

  7. JavaScript 中的数据类型

    Javascript中的数据类型有以下几种情况: 基本类型:string,number,boolean 特殊类型:undefined,null 引用类型:Object,Function,Date,Ar ...

  8. javascript中的操作符详解1

    好久没有写点什么了,根据博主的技术,仍然写一点javascript新手入门文章,接下来我们一起来探讨javascript的操作符. 一.前言 javascript中有许多操作符,但是许多初学者并不理解 ...

  9. Javascript中关于cookie的那些事儿

    Javascript-cookie 什么是cookie? 指某些网站为了辨别用户身份.进行session跟踪而储存在用户本地终端上的数据(通常经过加密).简单点来说就是:浏览器缓存. cookie由什 ...

随机推荐

  1. javascript的错误处理

    1 onerror事件,实例代码如下: <%@ Page Language="C#" AutoEventWireup="true" CodeBehind= ...

  2. Ranges用法

    RANGES语句:要用与选择表相同的结构创建内表,可使用RANGES语句,如下所示: 语法:RANGES <seltab> FOR <f>. 该语句创建选择表<selta ...

  3. DevExpress GridControl使用方法总结

    一.如何解决单击记录整行选中的问题 View->OptionsBehavior->EditorShowMode 设置为:Click 二.如何新增一条记录 (1).gridView.AddN ...

  4. Oracle之自动收集统计信息

    一.Oracle 11g 在Oracle的11g版本中提供了统计数据自动收集的功能.在部署安装11g Oracle软件过程中,其中有一个步骤便是提示是否启动这个功能(默认是启用这个功能). 在这里介绍 ...

  5. SharePoint 2013中Office Web Apps的一次排错

    转自http://www.cnblogs.com/awpatp/archive/2013/06/06/3121420.html, 仅供自己查看 笔者尝试在自己的测试环境中为SharePoint 201 ...

  6. 【转】从viewController讲到强制横屏,附IOS5强制横屏的有效办法

    文字罗嗦,篇幅较长,只需营养可直接看红字部分. 一个viewController的初始化大概涉及到如下几个方法的调用: initWithNibName:bundle: viewDidLoad view ...

  7. iOS开发之网络数据解析(一)--JSON解析简介

    前言:对服务器请求之后,返回给客户端的数据,一般都是JSON格式或者XML格式(文件下载除外) 本篇随便先讲解JSON解析. 正文: 关于JSON: JSON是一种轻量级的数据格式,一般用于数据交互 ...

  8. sublime text 3 修改文件保存编码

    File->Save With Encoding->UTF-8 with BOM

  9. 关于配置并发访问的服务器apache、nginx

    一. apache,nginx比较     关于Apache与Nginx的优势比较  (apache计算密集型   nginx io密集型  各有优势,不存在谁取代谁) 二.nginx 基于nginx ...

  10. jquery-qrcode生成二维码

    一.jquery-qrcode jquery-qrcode是一个为浏览器生成二维码的jquery插件.我们很容易将它集成到我们的应用.该插件也可以独立使用,也比较小.它是直接在客户端生成二维码生成.所 ...