//1.闭包概念:能够访问自身变量的函数
//2.自由变量:能够在函数中使用,但是不是该函数的局部变量的变量
//3.闭包 = 函数 + 函数能够访问的自由变量
//4.ecm 中闭包:即使创建他的上下文已经销毁,他任然存在;在代码中使用了自由变量。
举个栗子
var scope = 'global scope'; function checkScope(){ var scope = 'local scope'; function f(){ return scope } return f; } var foo = checkScope(); console.log(foo())
经典例子
var data = []; for (var i = 0; i < 3; i++) { data[i] = function () { console.log(i); }; } data[0]();//3 data[1]();//3 data[2]();//3 //添加闭包 var data = []; for (var i = 0; i < 3; i++) { data[i] = (function (i) { return function(){ console.log(i); } })(i); } data[0]();//1 data[1]();//2 data[2]();//3
原因:
当执行到 data[0] 函数之前,此时全局上下文的 VO 为:
globalContext = { VO: { data: [...], i: 3 } }
当执行 data[0] 函数的时候,data[0] 函数的作用域链为:
data[0]Context = {
Scope: [AO, globalContext.VO]
}
data[0]Context 的 AO 并没有 i 值,所以会从 globalContext.VO 中查找,i 为 3,所以打印的结果就是 3。
data[1] 和 data[2] 是一样的道理。
修改为闭包后:
当执行到 data[0] 函数之前,此时全局上下文的 VO 为:
globalContext = { VO: { data: [...], i: 3 } }
当执行 data[0] 函数的时候,data[0] 函数的作用域链发生了改变:
data[0]Context = {
Scope: [AO, 匿名函数Context.AO globalContext.VO]
}
匿名函数执行上下文的AO为:
匿名函数Context = { AO: { arguments: { 0: 0, length: 1 }, i: 0 } }
data[0]Context 的 AO 并没有 i 值,所以会沿着作用域链从匿名函数 Context.AO 中查找,这时候就会找 i 为 0,找到了就不会往 globalContext.VO 中查找了,即使 globalContext.VO 也有 i 的值(值为3),所以打印的结果就是0。
data[1] 和 data[2] 是一样的道理。