Skip to content

让你彻底理解delete

LYF edited this page Aug 15, 2016 · 23 revisions

delete在javascript中太复杂了,与其相关的知识就有:可执行代码类型、执行环境、变量对象、活动对象、eval函数、属性特性等

下面我就系统地梳理一下delete相关的知识,希望你看完这篇文章能够彻底理解delete。

1. 什么是delete

delete是javascript中的一个关键字,同时也跟typeof、void一样是运算符,其返回值为Boolean类型。

它用于 从对象中删除一个属性,或从数组中移除一个元素。

2. 从一个问题看delete

   // 下列代码是直接写在全局下的。GLOBAL_OBJECT为window对象或global对象
   var GLOBAL_OBJECT = this;

   var name = 'liyanfeng';

   delete name; // false

   console.log(name); // liyanfeng


   GLOBAL_OBJECT.age = 26;

   delete GLOBAL_OBJECT.age; // true

   console.log(GLOBAL_OBJECT.age); // undefined
   
 

上述代码中,name和age都是全局变量,但是为什么name不能被删除,而age能被删除呢?

2.1 可执行的代码类型

一共有 3 种 ECMA 脚本可执行代码:

  1. 全局代码

    是指被作为ECMA脚本程序所处理的源代码文本(source text),是直接在全局环境下执行的源代码文本。一个特定程序的源代码文本不包括作为函数体被解析的源代码文本。

  2. eval代码

    是指提供给内置函数eval的源代码文本(即eval函数的参数),更精确地说,如果传递给eval函数的参数为一个字符串,则该字符串将会被当作ECMA代码执行。

  3. 函数代码

    是指作为函数体被解析的源代码文本(即function内部的代码)一个函数体函数代码不包括嵌套函数的函数体代码。函数代码同时还特指一构造器方式调用Function内置对象时所提供的源代码文本,更精确地说,调用Function构造器时,传递的最后一个参数,将会转换为字符串并作为函数体使用,如果调用 Function 构造器时,传递了一个以上的参数,除最后一个参数以外的其他参数都将转换为字符串,并以逗号作为分隔符连接在一起成为一个字符串,该字符串被解析为 形参列表 供由最后一个参数定义的 函数体 使用。初始化 Function 对象时所提供的函数代码,并不包括作为其嵌套函数的 函数体 被解析的源代码文本。

2.2 执行环境和变量(活动)对象

在ECMA代码执行时,它总是处于某种执行环境下,执行环境是一个抽象的概念,可以帮助我们理解作用域和作用域链。每一种可执行代码都是在各自的执行环境中运行的。

执行环境在逻辑上形成一个栈,栈底是全局执行环境,每次调用一个函数,就会有新的执行环境入栈,函数执行完毕(return之后),此环境会弹出栈并被销毁。

每一种执行环境都有一个与其关联的叫做变量对象的东西,它用来确定它所在的执行环境中,有那些标识符对于当前环境内的代码是可见的。简言之,我们敲键盘写的javascript源代码,写好之后,我们在代码中声明的标识符会绑定到相应可执行代码类型的执行环境中的变量对象中,即作为变量对象的一个属性。

2.2.1 全局代码的执行环境中的变量对象

全局代码的执行环境中的变量对象是由全局对象(window or global object)充当的。这也是我们唯一可以用代码访问的变量对象。

  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

全局变量将会作为全局对象(同时也是全局执行环境的变量对象)的属性存在。

2.2.2 函数的执行环境中的变量对象

我们在函数代码中声明的变量和函数声明是怎么一种情况呢?我们把函数代码的执行环境中的变量对象称之为活动对象。

我们在函数代码中声明的局部变量、函数、函数参数、arguments对象,都是作为该函数的执行环境中的变量对象中的属性而存在。

(function(foo){

    var bar = 2;
    function baz(){}

    /*
      ACTIVATION_OBJECT为该函数执行环境中的活动对象

      `arguments` 对象 成为了ACTIVATION_OBJECT的一个同名属性
      ACTIVATION_OBJECT.arguments; // Arguments object

    ...参数 `foo`也一样:
      ACTIVATION_OBJECT.foo; // 1

    ...局部变量bar也一样:
      ACTIVATION_OBJECT.bar; // 2

    ...函数声明也一样:
      typeof ACTIVATION_OBJECT.baz; // "function"
    */

  })(1);

2.2.3 eval的执行环境中的变量对象

eval代码中声明的变量和函数,添加在调用eval函数的环境中的变量对象中,eval代码并没有自己单独的执行环境和变量对象。 简单来说:eval在那个环境中被调用,就把eval代码中的标识符添加到那个环境中的变量对象中

 var GLOBAL_OBJECT = this;

 /* `foo` 被作为调用eval函数的环境中的变量对象的一个属性。在本例中,此变量对象是全局对象*/

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

 (function(){

   /* `bar` 被作为调用eval函数的环境中的变量对象的一个属性,在本例中,是这个匿名函数的执行环境中的活动对象*/

   eval('var bar = 1;');

   /*
     ACTIVATION_OBJECT.bar; // 1
   */

 })();

3. 属性特性

参考:

  1. http://perfectionkills.com/understanding-delete/#theory

  2. https://developer.mozilla.org/zh-cn/docs/Web/JavaScript/Reference/Operators/delete

  3. https://msdn.microsoft.com/zh-cn/library/2b2z052x(v=vs.94).aspx

  4. http://yanhaijing.com/es5/#171

Clone this wiki locally