#1 作用域链 ##1.1 名词解释 执行环境:定义了变量或者函数有权访问的其它数据,每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中,我们编写的代码无法访问这个对象,但是解析器在处理数据时会在后台使用它。 **作用域链:**当代码在一个环境中执行时,会创建变量对象的一个作用域链,作用域链的用途是保证对执行环境有权访问的所有变量和函数的有序访问。作用域的前端,始终都是当前执行的代码所在环境的变量对象。如果这个环境是函数,则将其活动对象作为变量对象,活动对象在最开始时只包含一个变量,即argumeents对象(这个对象在全局环境中是不存在的)。作用域链中的下一个变量对象来自包含(外部)环境,而再下一个变量对象则来自下一个包含韩晶。这样一直延续到全局执行环境;全局执行环境的变量对象始终都是作用域链中的最后一个对象
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();
以上代码共涉及 3 个执行环境:全局环境、changeColor()的局部环境和 swapColors()的局部 环境。全局环境中有一个变量 color 和一个函数 changeColor()。changeColor()的局部环境中有 一个名为 anotherColor 的变量和一个名为 swapColors()的函数,但它也可以访问全局环境中的变 量 color。swapColors()的局部环境中有一个变量 tempColor,该变量只能在这个环境中访问到。 无论全局环境还是 changeColor()的局部环境都无权访问 tempColor。然而,在 swapColors()内部 则可以访问其他两个环境中的所有变量,因为那两个环境是它的父执行环境
##1.2 作用域链创建过程 当某个函数被调用时,会创建一个执行环境以及相应的作用域链,然后使用arguments和其它命名参数的值来初始化函数的活动对象
后台的每个执行环境都有一个表示变量的对象——变量对象,全局的变量对象始终存在,而像compare()函数这样的局部环境的变量对象,则只在函数的执行过程中存在,在创建compare函数时,1)会创建一个预先包含全局变量对象的作用域链;2)此后,又有一个活动对象(再次作为变量对象使用,一开始会包含arguments)被创建并被推入执行环境作用域链的前端(会先于全局变量对象),作用域链的本质是一个指向变量对象的指针列表,它只引用但不实际包含变量对;一般来讲当函数执行完毕后,局部活动对象就会被销毁,内存中仅保存全局变量对象,但是闭包又有所不同
#2 闭包 闭包是指有权访问另一个函数作用域中变量的函数,创建闭包的常见方式,就是在函数内部创建另一个函数;
function createComparisonFunction(propertyName) {
return function(object1, object2){
var value1 = object1[propertyName];
var value2 = object2[propertyName];
if (value1 < value2){ return -1;
} else if (value1 > value2){
return 1;
} else {
return 0;
}
};
}
//创建函数
var compare = createComparisonFunction("name");
//调用函数
var result = compare({ name: "Nicholas" }, { name: "Greg" });
//解除对匿名函数的引用(以便释放内存)
compareNames = null;
内部函数(一个匿名函数)中的代码,访问了外部 函数中的变量 propertyName。即使这个内部函数被返回了,而且是在其他地方被调用了,但它仍然可 以访问变量 propertyName。之所以还能够访问这个变量,是因为内部函数的作用域链中包含 createComparisonFunction()的作用域,在一个函数内部定义的函数会将包含函数(即外部函数)的活动对象添加到它的作用域链中,因此包含函数(外部函数)即使执行完毕之后,其活动对象也不会被销毁,因为匿名函数的作用域链仍然在引用包含函数(外部函数)的活动对象,所以活动对象并不会被销毁,仍然会保留在内存中,知道匿名函数被销毁后,包含函数(外部函数)的活动对象才会被销毁。

*注意点:*this在匿名函数中执行环境具有全性,因此this常常指向的是window,每个函数在被调用时都会自动取得两个特殊的变量:this和arguments。内部函数在搜索这两个变量时,只会搜索到其活动对象为止,因此永远不会访问外部函数中的这两个变量