个人理解
var data = [];
for (var i = 0; i < 3; i++) {
data[i] = (function (i) {
return function(){
console.log(i);
}
})(i);
}
data[0]();//0
data[1]();//1
data[2]();//2
上面的循环相当与做了下面的事
var data = [];
data[0] = (function (i) {
return function(){
console.log(i);
}
})(0);
//相当于
data[0] = function(){
console.log(0);
}
data[1] = (function (i) {
return function(){
console.log(i);
}
})(1);
//相当于
data[1] = function(){
console.log(1);
}
data[2] = (function (i) {
return function(){
console.log(i);
}
})(2);
//相当于
data[2] = function(){
console.log(2);
}
data[0]();//0
data[1]();//1
data[2]();//2
声明了三个自执行函数,这三个函数之间是没有联系的,每个都是独立的(相当于3个实例,参考下面的makeAdder函数和makeCounter函数)
data[0] 、 data[1] 、data[2] 都是闭包。它们共享相同的函数定义,但是保存了不同的词法环境。在 data[0] 的环境中,i 为 0。在 data[1] 的环境中,i 为 1。在 data[2] 的环境中,i 为 2。
网上案例
闭包是通过作用域链来将函数内部变量保存在内存中
function f1(){
var n=999;
nAdd=function(){n+=1}
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result(); // 999
nAdd();
result(); // 1000
这段代码中另一个值得注意的地方,就是”nAdd=function(){n+=1}”这一行,首先在nAdd前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。此处摘自阮一峰
function makeAdder(x) {
return function(y) {
return x + y;
};
}
var add5 = makeAdder(5);
var add10 = makeAdder(10);
console.log(add5(2)); // 7
console.log(add10(2)); // 12
add5 和 add10 都是闭包。它们共享相同的函数定义,但是保存了不同的词法环境。在 add5 的环境中,x 为 5。而在 add10 中,x 则为 10。
var makeCounter = function(){
var privateCounter = 0
function changeBy(val){
privateCounter += val
}
return {
increment:function(){
changeBy(1)
},
decrement:function(){
changeBy(-1)
},
increment:function(){
return privateCounter
}
}
}
var Conter1 = makeCounter();
var Conter2 = makeCounter();
console.log(Counter1.value()); /* logs 0 */
Counter1.increment();
Counter1.increment();
console.log(Counter1.value()); /* logs 2 */
Counter1.decrement();
console.log(Counter1.value()); /* logs 1 */
console.log(Counter2.value()); /* logs 0 */
请注意两个计数器 Counter1 和 Counter2 是如何维护它们各自的独立性的。每个闭包都是引用自己词法作用域内的变量 privateCounter 。
每次调用其中一个计数器时,通过改变这个变量的值,会改变这个闭包的词法环境。然而在一个闭包内对变量的修改,不会影响到另外一个闭包中的变量。
以这种方式使用闭包,提供了许多与面向对象编程相关的好处 —— 特别是数据隐藏和封装。