执行环境和作用域的关系?
执行环境,也称执行上下文(Execution context,EC),都有与之关联的作用域(链)。每个执行环境会向上搜索作用域链进而形成一个自己的作用域。
1.执行环境及作用域
- 执行环境(环境): 定义了变量或函数有权访问的其他数据,决定了他们各自的行为。每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个变量对象中。 
- 全局执行环境是最外围的一个执行环境。在浏览器中,全局执行环境就是window对象。 
- 执行环境分全局执行环境(全局环境)和函数执行环境。每个函数都有自己的执行环境。 
- ECMAScript执行流机制:当执行流进入一个函数时,函数的环境就会被推入一个环境栈中。而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境。等价于:某个执行环境中的所有代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之销毁。 
- 作用域链: 当代码在一个环境中执行时,会创建变量对象的一个作用域链。其用途,是保证对执行环境有权访问的变量和函数的有序访问。 
- 作用域链结构:作用域链前端,始终是当前执行的代码所在环境的变量对象,而下一个变量对象则是来自包含它的外部环境。这样,一直延续到全局执行环境。 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14- var color="blue"; 
 function changeColor(){
 if(color==="blue"){
 color="red";
 }else{
 color="blue";
 }
 }
 changeColor();
 alert("Color is now"+color); //结果是red
 //函数changeColor()作用域链包含两个变量对象:
 //自己的变量对象(其中定义着arguments对象)
 //全局环境的变量对象。
- 局部作用域中定义的变量可以在局部环境中与全局变量互换使用。 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14- var color="blue"; 
 function changeColor(){
 var anotherColor="red";
 function swapColors(){
 var tempColor=anotherColor;
 anotherColor=color;
 color=tempColor;
 //这里可以访问color、anotherColor和tempColor
 }
 //这里可以访问color、anotherColor,不能访问tempColor
 swapColors();
 }
 //这里只能访问color
 changeColor();
作用域如下图:
作用域链规则:执行环境之间的联系是线性、单向、有次序的。
每个环境可以向上搜索作用域链,以查询变量和函数名;但任何环境都不能通过向下搜索作用域链而进入另一个执行环境。
2.延长作用域链
- 怎么延长:有些语句在(其父)作用域链的前端临时增加一个变量对象,该变量对象会在代码执行后被移除。
- 两个语句:- with语句:将指定对象添加到(其父)作用域的前端
- try-catch语句的catch块:会创建一个新的变量对象,其中包含的是被抛出的错误对象的声明。- 1 
 2
 3
 4
 5
 6
 7
 8- function buildUrl(){ 
 var qs="?debug=true";
 with(location){
 var url=href+qs;
 }
 return url;
 }
 //with语句将其变量对象添加到buildUrl()作用域链前端,buildUrl()可以访问url变量了。
 
3.没有块级作用域
块级作用域指:类C语言中,花括号封闭的代码块都有自己的作用域(EMAScript中是执行环境),花括号内的代码执行完后变量和函数定义会被销毁。而Javascript没有块级作用域。
3.1 声明变量
- 使用var声明的变量会自动被添加到最近的环境中。
- 在函数内部,最接近环境是函数的局部变量
- 在with语句中,最接近环境的函数环境。
3.2 查询标识符
- 从作用域前端开始,逐渐向上查询,查到就停止。
- 访问局部变量比全局变量快。
