JavaScript高程浅入浅出之 执行环境(执行上下文)及作用域

234 阅读5分钟

执行环境(execution context)也叫执行上下文,是用来判断变量或函数的作用域,即在程序中使用到一个变量时候要在什么范围内去寻找它的定义值。或者说是规定了变量或函数有权访问的数据。

那么执行环境是如何创建的呢?变量如何根据执行环境去找它的值呢?下面给出一个例子:

var color = "blue";
function findColor() {
    var tag = "red";
    if (color == tag){
        return true;
    }else{
        return false;
    }
}

alert("find red?"+findColor() );

首先抛出一个问题,findColor( )函数中用到的变量color去哪里找呢?很明显大家会定位到第一行的

var color = "blue";

那么JS是如何进行这个变量搜索的呢?主要就是运用执行环境和作用域链的方式。下面我们需要知道执行环境是怎么创建的

执行环境

**创建:    **执行环境的创建主要有两种,一是遇到函数定义就创建一个该函数的执行环境,函数定义中的所有代码都处于该函数的执行环境中。二是全局有一个执行环境,不在函数中的代码都是位于全局执行环境。所有的代码行都有自己所处的执行环境,因此加入没有这个全局执行环境,那不在函数定义中的代码例如 var color = "blue" ; 不就没有了自己所在的执行环境吗?因此这两个执行环境能够把所有的代码都放在对应的环境中。

上述的例子中一共有两个执行环境:全局执行环境和findColor()的局部执行环境。

变量对象:    执行环境定义了变量或函数有权访问的数据,每个执行环境通过关联的变量对象来确定处于本执行环境内的代码行能够使用的变量和函数是哪些,变量对象中的内容是所有在这个环境中定义的变量或者函数,因此变量对象是一个大集合。但是这个变量对象的生成维护靠后台或浏览器的JS解析器,我们无法访问。

上面的例子中,遇到findColor( )函数的定义,就创建出findColor( )的局部执行环境,这个环境中的变量对象包括 tag 。由于 color 不是在函数内部定义,因此不在其变量对象中。而在浏览器中全局环境的变量对象是window对象,因此在全局环境中定义的color以及findColor( )函数都在window这个变量对象中。

代码所在的执行环境能够访问该执行环境的变量对象。因此在全局中可以访问color变量以及findColor( )函数,findColor( )函数的局部执行环境中的代码可以访问 tag 变量。但是 findColor( )函数的局部执行环境中的代码访问了全局中的 color 变量是怎么理解呢,这时候就需要开头提出的作用域链了!

注:JS 没有块级作用域(执行环境)

因为前面所说的执行环境是由函数定义的局部执行环境和全局执行环境。因此在JS中代码块如 if,while语句不能产生自己的执行环境。例如:

if (true) {
    var color = "blue";
}
alert(color);  // 输出:"blue"

在 if 代码块中定义的变量color是存在于全局执行环境中,因此在alert函数中能够访问。处理的时候把花括号封闭起来的代码块当成普通的代码语句进行处理即可。在其他的类C语言例如C++,Java等,是能够产生自己的作用域的。JS没有块级作用域。

作用域链

当代码进入一个执行环境时候,会将该环境中的变量对象里的东西都拿出来,所有的执行环境的变量对象创建出一条作用域链,作用是保证代码对变量和函数的有序访问,特别是不同函数(执行环境)中有同名变量时候。

拿开头的例子说,按照代码的执行顺序来创造这个链条。首先是执行代码

var color = "blue";

这是全局执行环境,window作为作用域的起点,其变量对象中有两个,color和findColor( ),因此链条window孩子节点是并排的color和findColor( )。接着执行

alert("find red?"+findColor() );

遇到findColor( )函数,进入findColor( )的执行环境中,执行函数中的语句,findColor( )环境的变量对象中有tag,因此 tag 作为 findColor( ) 的子节点加到链条的后面,如下图所示:

每个颜色代表其执行环境,在环境中的代码可以在本环境中或者沿着链条向上搜索其他环境中自己需要的变量或函数,但是不能向下搜索。即内部环境可以通过作用域链访问所有的外部环境,但是外部环境不能访问内部环境中的函数或者变量。

因此在findColor( )环境中的代码使用到color,但是当前链条节点的的变量对象只有tag时候,它会沿着链条往上找,找到外部环境window中的color变量进行访问读取。

环境栈:    那么如何知道这些代码是位于哪个执行环境呢,我们当然能够很容易的看出来,对于计算机来说是如何实现的?是使用栈实现。

当执行流进入一个执行环境时候,就把这个执行环境入栈,这个栈专门保持环境的。当函数执行完毕后就把这个函数的环境出栈,这样只要函数内的未执行完毕,就可以通过栈顶判断当前的执行环境,找到这个执行环境包含的作用域链条的节点,沿着节点往上搜索访问需要用到的变量和函数。

当一个执行环境出栈时候,里面的变量对象也就全部销毁。

如果有误请大家不吝赐QAQ