一. 执行环境
执行环境( execution context
)是 JavaScript
中最为重要的一个概念。执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。
每个执行环境都有一个与之关联的 变量对象(variable object
),环境中定义的所有变量和函数都保存在这个对象中。
虽然我们编写的代码无法访问这个对象,但解析器在处理数据时会在后台使用它。
全局执行环境是最外围的一个执行环境。在 Web
浏览器中,全局执行环境被认为是 window
对象,
因此所有全局变量和函数都是作为window
对象的属性和方法创建的。
对全局执行环境变量来说,变量对象 就是window
对象,
对函数来说,变量对象就是这个函数的 活动对象 ( 活动对象是在函数调用时创建的一个内部变量 )
每个函数都有自己的执行环境,当执行流进入一个函数时,函数的执行环境就会被推入一个执行环境栈中。
而在函数执行之后,栈将执行结束的函数的执行环境弹出,把控制权返回给之前的执行环境。
二. 作用域链
作用域链与一个执行环境相关,作用域链用于变量查找。
在JavaScript
中,函数也是对象,实际上,JavaScript
里一切都是对象。
函数对象和其它对象一样,拥有可以通过代码访问的属性和一系列仅供JavaScript
引擎访问的内部属性。
其中一个内部属性是[[Scope]]
,由ECMA-262
标准第三版定义,他就指向了这个函数的作用域链。
作用域链中存储的是与每个执行环境相关 变量对象 (函数内部也是活动对象)。
当创建一个函数( 声明一个函数 )后,那么会创建这个函数的作用域链。这个函数的作用域链在这个时候只包含一个变量对象(window
)
function sum(num1, num2){
var sum = num1 + num2;
return sum;
}
函数 sum 的作用域链示意图:
说明:
- 函数创建的时候,这个时候作用域链中只有一个 变量对象 (window)
当执行下面的代码:
<script type="text/javascript">
function sum(num1, num2){
var sum = num1 + num2;
return sum;
}
var sum = sum(3, 4);
</script>
说明:
当调用
sum
函数时,会首先创建一个 “执行环境”,这个 执行环境 有自己的作用域链,这个作用域链初始化为
sum
函数的[[scope]]
所包含的对象。然后创建一个 与这个执行环境相关的 变量对象( 活动对象 ) ,这个 变量对象 中存储了在这个函数中定义的所有参数、变量和函数。把 变量对象 存储在作用域中的顶端。
以后在查找变量的时候,总是从作用域链条的顶端开始查找,一直到作用域链条的末端。
看下面的示意图:
说明:
在sum中访问一个变量的时候,总是从作用域链的顶端开始查找,如果找到就得到结果,如果找到不到就一直查找,直到作用域链的末端。
因为在方法内的存在变量和函数的声明提前现象,所以函数一旦执行 函数的活动对象(变量对象)中总是保存了这个函数中声明的所有变量和函数。
如果在函数中又定义了一个内部函数(还没有执行),则这个时候内部函数的作用域,是包含了外部函数的作用域。 一旦内部函数开始执行则把自己的活动对象添加到了这个作用域的顶端。
<script type="text/javascript">
function sum(num1, num2){
var sum = num1 + num2;
function inner (a) {
}
return sum;
}
var sum = sum(3, 4);
</script>
内部函数的作用域:
函数执行后的作用域示意图不再画出。