执行环境和作用域的关系?
执行环境,也称执行上下文(Execution context,EC),都有与之关联的作用域(链)。每个执行环境会向上搜索作用域链进而形成一个自己的作用域。
1.执行环境及作用域
执行环境(环境): 定义了变量或函数有权访问的其他数据,决定了他们各自的行为。每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个变量对象中。
全局执行环境是最外围的一个执行环境。在浏览器中,全局执行环境就是window对象。
执行环境分全局执行环境(全局环境)和函数执行环境。每个函数都有自己的执行环境。
ECMAScript执行流机制:当执行流进入一个函数时,函数的环境就会被推入一个环境栈中。而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境。等价于:某个执行环境中的所有代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之销毁。
作用域链: 当代码在一个环境中执行时,会创建变量对象的一个作用域链。其用途,是保证对执行环境有权访问的变量和函数的有序访问。
作用域链结构:作用域链前端,始终是当前执行的代码所在环境的变量对象,而下一个变量对象则是来自包含它的外部环境。这样,一直延续到全局执行环境。
1
2
3
4
5
6
7
8
9
10
11
12
13
14var 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
14var 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
8function 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 查询标识符
- 从作用域前端开始,逐渐向上查询,查到就停止。
- 访问局部变量比全局变量快。