参考《JavaScript高级程序设计》
预备
执行环境定义了变量或函数有权访问的其他数据
每个函数都有自己的执行环境
每个执行环境都有一个与之关联的变量对象
当代码在一个环境中执行时,会创建变量对象的一个作用域链( scope chain)。
作用域链的用途:保证对执行环境有权访问的所有变量和函数的有序访问。
闭包
有权访问另一个函数作用域中的变量的函数。
创建闭包的常见方式:在一个函数内部创建另一个函数
区别
在函数中访问一个变量时,就会从作用域链中搜索具有相应名字的变量。
一般来讲,当函数执行完毕后,局部活动对象就会被销毁,内存中仅保存全局作用域(全局执行环境的变量对象)。
但是在另一个函数内部定义的函数(闭包)会将包含函数(即外部函数)的活动对象添加到它的作用域链中。
实验代码
/**
* 返回根据属性propertyName对两个对象的比较方法
*/
function createComparisonFunction(propertyName) {
let globalVal = "ok";
return function(object1, object2) {
console.log("createComparisonFunction作用域中的globalVal是, ", globalVal);
let value1 = object1[propertyName];
let value2 = object2[propertyName];
if (value1 < value2){
return -1;
} else if (value1 > value2){
return 1;
} else {
return 0;
}
};
}
/**
* 测试闭包会将包含函数的活动对象添加到它的作用域链中
*/
function test1(){
let p1 = {"age": 10};
let p2 = {"age": 11};
let cmpFunc = createComparisonFunction("age");
console.log("p1和p2的比较结果是", cmpFunc(p1, p2));
//注意下面第二次执行cmpFunc的时候依然可以获取globalVal的值
console.log("p2和p1的比较结果是", cmpFunc(p2, p1));
//解除引用,释放内存
comFunc = null;
}
test1();
//输出如下
createComparisonFunction作用域中的globalVal是, ok
p1和p2的比较结果是 -1
createComparisonFunction作用域中的globalVal是, ok
p2和p1的比较结果是 1
特殊
闭包只能取得包含函数中任何变量的最后一个值。
别忘了闭包所保存的是整个变量对象,而不是某个特殊的变量。
代码:注意for循环中使用了var
/**
* 返回函数数组
*/
function createArrayByFunctions(){
let result = [];
for(var i = 0; i < 10; i++) {
result[i] = function() {
return i;
};
}
return result;
}
/**
* 测试函数数组的函数值
*/
function test2(){
let arr = createArrayByFunctions();
arr.forEach(item => {
process.stdout.write(item()+" ")
});
}
test2();
//输出
10 10 10 10 10 10 10 10 10 10
意外:把var换为let,结果正常
分析:let
是块级作用域,而 var
是函数作用域。使用let时每一个不同值的i都因为闭包所以保存下来。
0 1 2 3 4 5 6 7 8 9