执行环境及作用域链
执行环境定义了变量或函数有权访问的其他数据,确定了它们各自的行为。每个执行执行环境都有一个与之关联的变量对象,这个变量变量对象保存着环境中定义的所有变量和函数。
全局执行环境就是最外围的一个执行环境。根据 ECMAScript 实现,所在的环境不同,表示的执行环境的对象页不一样。在浏览器中,全局执行环境被认为 window 对象。因此,在全局声明的属性和方法都是 window 对象的属性和方法。
var a = 1;
console.log( window.a ) //1
window.b = 2;
console.log( b ) //2
在某个执行环境中的所有代码执行后,改环境被销毁,保存其中的所有变量和函数定义也随之销毁( 全局执行直到应用退出——退出浏览器是才会被销毁)。
当代码在一个环境中执行时,会创建变量对象的一个作用域链。
作用域链的作用: 保证对有权访问的所有变量和函数进行有序的访问。
在作用域的前端,始终是当前执行的代码所在的 变量对象。如果这个环境是函数,活动对象就是变量对象。活动对象最开始只包含一个变量,即 ( arguments ) 对象(这个对象在全局环境是不存在的)。作用域链中的下一个变量对象来自包含环境,而再下一个变量对象则来自下一个包含环境。这样,一直延续到全局环境;全局执行环境的变量对象始终是最后一个对象。
var color = "blue";
function changeColor() {
if( color === "blue") {
color = "red";
} else {
color = "blue";
}
}
changeColor();
alert()
在上面的例子中, 函数 changeColor() 的作用域链包含两个对象:它自己的变量对象(其中定义这 arguments 对象 )和全局环境的变量对象。所以可以在函数内部访问变量 color。
2. 查找标识符
查找标识符的过程从作用于链的前端开始,向上逐级查找给定名字匹配的标识符。如果在局部环境中找到了该标识符,则查找停止,变量就绪。如果在局部环境没有找到该标识符,则沿作用域上查找。查找过程将一直追溯到全局的变量的变量对象。如果在全局环境中也没有找到这个标识符,则意味着该变量为声明。
var color = "blue";
function getColor() {
return color;
}
alert(getColo()); // blue
上面例子中调用了 getColor() 函数会引用变量 color 。为了确定 color 的值。就会沿着作用链向上搜索。
首先,搜索 getColor() 的变量对象,查找其中是否有个名叫color 的标识符。在没有找到的情况下,继续搜索下一个变量对象(全局环境的变量对象),在全局变量对象中搜索到了color,搜索结束。
在搜索过程中,如果存在一个局部变量的定义,则搜索会自动停止,不在进入另一个变量对象。换句话说,如果局部环境中存在着同名的标识符,就不会使用位于父环境中的标识符。例子:
var color = "blue";
function getColor() {
var color = red;
return color;
}
alert(getColo()); // red
内部环境可以通过作用域链访问所有的外部环境,但是外部环境不能访问内部环境中的任何变量和对象。每个环境都可以上搜索作用域链,已查询变量和遍历和函数名。但任何环境都不能通过向下搜索作用域链。