闭包
JavaScript 中闭包无处不在,你只需要能够识别并拥抱它。
什么是闭包
function foo() {
var a = 2;
function bar() {
console.log( a ); // 2
}
bar();
}
foo();
// 上面的并不算是闭包,只是闭包的一部分
function foo() {
var a = 2;
function bar() {
console.log( a );
}
return bar;
}
var baz = foo();
baz(); // 2 —— 朋友,这就是闭包的效果
- 上面的例子
- 执行完后,foo 的内部作用域被销毁
- 下面的例子
- 闭包的“神奇”之处,foo 的内部作用域都没有被销。
所以什么是闭包
函数在定义时的词法作用域以外的地方被调用。闭包使的函数可以继续访问定义时的作用域。
关键字
- 定义时的词法作用域之外
- 继续访问定义时的作用域
闭包的应用
- 定时器
- 事件监听器
- Ajax 请求
- 跨窗口通信
- Web Workers
看个面试题
for (var i=1; i<=5; i++) {
setTimeout( function timer() {
console.log(i);
}, i*1000)
}
答案是:5个6
为什么
首先是 6 是从哪里来的,这个循环的终止条件是 i 不再 <=5,条件成立时,i 等于 6。
第二个,延迟函数会等循环结束之后再执行,所以当延迟函数执行完时,i 已经等于 6。
解决方法:
- let,const
- 给每个 setTimeout 弄个单独的作用域,IIFE
for (var i=1; i<=5; i++) {
(function(j) {
setTimeout( function timer() {
console.log(j);
}, j*1000)
})(i)
}
闭包的作用
模块化
function CoolModule() {
var something = "cool";
var another = [1, 2, 3];
function doSomething() {
console.log( something );
}
function doAnother() {
console.log( another.join( " ! " ) );
}
return {
doSomething: doSomething,
doAnother: doAnother
};
}
var foo = CoolModule();
foo.doSomething(); // cool
foo.doAnother(); // 1 ! 2 ! 3
小结
闭包是什么
函数在定义时的词法作用域以外的地方被调用。闭包使的函数可以继续访问定义时的作用域。
- 定义时的作用域之外调用
- 能够访问定义时的内部作用域