一、执行上下文 

  当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 
*/ 

})();






二 “预编译”

   Javascript按照<script>段的方式进行预编译处理相关的代码段,并且按照先预定义变量,再预定义函数的方式进行预编译!而且无论变量/函数在段中的任何地点进行显式声明(在变量前加var),都会在所有代码执行前进行预编译,并且变量的值初始为undefined,函数变量的初始值为函数体,下面我们使用示例代码来说明整体的预编译情况:

    

	alert(f);//function f(){ return1;}
	alert(b);//undefined
	alert(a);//undefined
	var a = function (){
		return 2;
	}
	function f (){             /
			return 1;   
	};
	var b = 10;


    覆盖:按照下列顺序,var a 被预编译为undefined,a被预编译为"functiona(){return1;}",a被预编译为"functiona(){return10;}",所以最后a为"functiona(){return10;}"

	alert(a);//function a (){return 10;};
	
	
	function a (){             
			return 1;   
	};
	function a (){             
			return 10;   
	};
	var a = 123;