* 先看一下当某个函数第一次被调用时,会发生什么?
* 会创建一个执行环境,及相应的作用域链,并把作用域赋值给一个特殊的内部属性[[Scope]]。
* 然后使用this,agrguments和其他命名参数(就是函数定义的参数)的值来初始化函数的活动对象。
* 在作用域链中,外部函数的活动对象始终处于第二位,外部函数的外部函数的活动对象处于第三位,...直至作用域链终点的全局执行环境。
* 在函数执行过程中,为读取和写入变量的值,就需要在作用域链中查找变量。详见示例1
/*************************************************************************************************************
* 示例1
*/
function compare(value1, value2) {
if (value1 < value2) {
return -1;
} else if (value1 > value2) {
return 1;
} else {
return 0;
}
}
var result = compare(); //当第一次调用compare()函数时,会创建一个包含this、arguments、value1、value2的活动对象,处在第一位
//这里是在全局函数中调用的compare()函数,全局执行环境的变量对象(包含this、result、compare)在执行环境作用域链中处于第二位。
/****************************************************************************************************************
compare()函数执行时的作用域链关系:
/*
* 后台的每个执行环境都有一个表示变量的对象-变量对象。全局环境的变量对象始终存在
* 而像compare()函数这样的局部环境的变量对象,只有在函数执行的过程中存在
* 创建函数时,会创建一个预先包含全局活动对象的作用域链,保存在内部[[Scope]]属性中
* 调用函数时,会为函数创建一个执行环境,然后通过复制函数[[Scope]]属性中的对象构建起执行环境的作用域链
* 此后,又创建一个活动对象(作为变量对象)并把它推到执行环境作用域链的前端。
* 拿compare()函数的执行环境而言,其作用域链包含两个变量对象:本地活动对象和全局变量对象。
* 作用域链本质是一个指向变量对象的指针,它只引用但不实际包含变量对象
*/
/****************************************************************************************************************
* 闭包
* 创建闭包的常见方式:
* 在一个函数内部(外部函数)定义另一个函数(内部函数)
* 会把外部函数的活动对象添加到内部函数的作用域链中
*
*/
function createComparisonFunction(propertyName) {
return function (object1, object2) {
/**
* 下面两行代码是内部函数中的代码,这两行代码访问了外部函数中的变量propertyName;
* 之所以能够访问这个变量是因为内部函数的作用域链中包含createComparisonFunction()的作用域
**/
var value1 = object1[propertyName];
var value2 = object2[propertyName];
if (value1 < value2) {
return -1;
} else if (value1 > value2) {
return 1;
} else {
return 0;
}
}
}
//内部函数被返回,这个匿名函数的作用域链中被初始化为包含外部函数的活动对象和全局变量对象
//内部函数可以访问外部函数定义的变量
//外部函数执行完毕后,其活动对象不会销毁,因为返回的内部函数作用域链仍然在引用这个活动对象
//换句话说,当createComparisionFunction()函数返回后,其执行环境的作用域链会被销毁,但活动对象仍然留在内存中,直到匿名函数被销毁,该活动对象才被销毁。
var compare = createComparisonFunction("name");
var result = compare({ name: "Nicholas" }, { name: "Greg" });
//解除对匿名函数的引用(通知垃圾回收例程将其清除),createComparisonFunction 的活动对象才被销毁。
compare = null;