关于闭包
词法作用域(lexical environment)
作用域链
- 函数在执行的过程中,先从自己内部找变量
- 如果找不到,再从创造当前函数所在的作用域(词法作用域)去找,以此往上
- 注意找的是变量的当前状态
函数连同它作用域链上的要找的这个变量,共同构成闭包
一般情况下使用闭包住要是为了
- 封装数据
- 暂存数据
例子
1 2 3 4 5 6 7 8 9 10
| var fnArr = []; for (var i = 0; i < 2; i++){ fnArr[i] = (function(j){ return function(){ return j } })(i) }
fnArr[1]()
|
这个例子里有两个闭包,
相当于可以将for循环拆开,等效于以下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| fnArr[0] = (function(j){ return function(){ return j; } })(0)
fnArr[1] = (function(j){ return function(){ return j; } })(1)
fnArr[1]();
|
再简化一下,写成a,b 函数
1 2 3 4 5 6 7 8 9 10 11 12 13
| var a = (function(j){ return function(){ return j; } })(0)
var b = (function(j){ return function(){ return j; } })(1)
b();
|
再同步一下,将var b里的立即执行函数单独拆出来,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| var a = (function(j){ return function(){ return j; } })(0)
function fn2(j){ var j = arguments[0]; return function(){ return j; } }
var b = fn2(1);
b();
|
其他的等效方法
方法1:
1 2 3 4 5 6 7
| var fnArr = [];
for(var i = 0; i < 2; i++){ fnArr[i] = (function(j){ return j; })(i) }
|
方法2:
1 2 3 4 5 6 7 8
| var fnArr = []; for(var i = 0;i < 2; i++){ (function(i){ fnArr[i] = function(){ return i; } })(i) }
|
方法3:(使用ES6)
1 2 3 4 5 6
| var fnArr = []; for(let i = 0; i < 10; i++){ fnArr[i] = function(){ return i; } }
|
闭包例题
封装一个Car对象
可以将其封装成一个对象返回,由于形成闭包,当调用方法时,不会对原有的参数speed进行影响。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| var Car = (function(){ var speed = 0; function setSpeed (s) { speed = s; }
function getSpeed (){ return speed }
function speedUp(){ speed++ }
function speedDown(){ speed --; } return { setSpeed: setSpeed, getSpeed: getSpeed, speedUp: speedUp, speedDown: speedDown } })()
|