删除Javascript Object中间的key(2)
当一段源代码被看成程序(Program)时, 它将会在全局环境下被执行, 并且被认为是全局代码(Global code). 在一个浏览器环境中, 脚本元素的内容通常被解释为程序, 因此被作为全局代码来执行.
任何直接在一个函数中执行的代码显然被认为是函数代码(Function code). 在浏览器中, 事件属性的内容(如 <p onclick="....">)通常被解释成函数代码.
最后, 被应用到内置函数eval的代码文本被解释成Eval代码(Eval code). 很快我们会发现为什么这种类型是特殊的.
执行上下文(Execution context):
当ECMAScript代码执行时, 它通常会发生在特定的执行上下文中.执行上下文是一个有些抽象的实体概念, 它能帮助理解范围(Scope)和变量实例(Variable instantiation)是如何工作的. 对三种可执行代码的每一种, 都有一个执行上下文相对应. 当一个函数被执行的时候, 我们说"程序控制进入了函数代码的执行上下文"; 当一段全局代码被执行时, 程序控制进入了全局代码的执行上下文, 等等.
正如你所见, 执行上下文可以在逻辑上构成一个堆栈. 首先, 可能有一段全局代码和其自己的执行上下文, 然后这段代码可能会调用一个函数, 并带着它(函数)的执行上下文. 这段函数可以调用另外一个函数, 等等等等. 即使函数是递归调用的, 每次调用时被也会进入一个新的执行上下文.
活动对象(Activation object) / 变量对象(Variable Object):
每一个执行上下文都有一个跟其所关联的所谓变量对象(Variable Object). 类似于执行上下文, 变量对象是一个抽象实体, 一种用来描述变量实例的机制. 有趣之处在于, 在源代码中声明的变量和函数通常会被当做属性(properties)增加到这个变量对象上.
当程序控制进入全局代码的执行上下文时, 一个全局对象(Global 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
好, 所以全局变量会变成全局对象的属性, 但是局部变量(那些在函数代码中定义的变量)会发生什么呢? 其实它们的行为也非常类似: 它们会变成变量对象(Variable object)的属性. 唯一的不同在于, 当在函数代码中时, 一个变量对象并不是全局对象, 而是所谓的活动对象(Activation object). 活动对象在会每次进入函数代码的执行上下文时被创建.
并不是只有在函数代码中声明的变量和函数会变成活动对象的属性; 这也会在每个函数参数(对应相应的形式参数的名称)和一个特殊的Arguments对象(以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代码中声明的变量会成为调用者上下文(calling context)的变量对象的属性. Eval代码只是简单地使用调用它的代码的执行上下文的变量对象.
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
*/
})();
属性的特性(property attributes)