这是我参与8月更文挑战的第8天,活动详情查看:8月更文挑战markdown
MDN 对闭包的定义为:闭包
闭包是指那些可以访问自由变量的函数。app
那什么是自由变量呢?异步
自由变量是指在函数中使用的,但既不是函数参数也不是函数的局部变量的变量。ide
由此,咱们能够看出闭包共有两部分组成:函数
闭包 = 函数 + 函数可以访问的自由变量post
简单来说:ui
闭包就是可以读取其余函数内部变量的函数lua
在函数 A 中还有函数 B,函数 B 调用了函数 A 中的变量,那么函数 B 就称为函数 A 的闭包。url
function foo() {
let a = 2;
function bar() {
console.log(a);
}
bar();
}
foo(); // 2
复制代码
for (var i = 0; i < 5; i++) {
setTimeout(function () {
console.log("i: ", i);
}, 1000);
}
console.log(i);
// 输出
// 5;
// i: 5;
// i: 5;
// i: 5;
// i: 5;
// i: 5;
复制代码
要理解上述代码,首先咱们得了解一下概念:
上述代码中使用定时器,当 JS 引擎线程执行到该段代码,便把定时器放到定时器线程去计时,此时 JS 引擎线程执行同步栈里面的任务。当定时器计时完成以后,将回调函数推入消息队列。等待栈中的代码执行完毕以后会去读取消息队列中的事件。
因为 JS 的函数做用域,当回调函数被推入消息队列的时候没有带上参数。for 循环结束以后,由于 i 是用 var 定义的,因此 var 是全局变量(这里没有函数,若是有就是函数内部的变量),这个时候的 i 是 5。
如何解决?
// let 是块级做用域,当前块是循环体
for (let i = 0; i < 5; i++) {
setTimeout(function() {
console.log('i: ',i);
}, 1000);
}
console.log(i);
// 输出
// 5
// i: 0
// i: 1
// i: 2
// i: 3
// i: 4
复制代码
//这是函数级做用域,利用闭包模拟块级做用域
for (var i = 0; i < 5; i++) {
(function(){
var j = i;
setTimeout(function() {
console.log('i: ',j);
}, 1000);
})();
}
console.log(i);
// 输出
// 5
// i: 0
// i: 1
// i: 2
// i: 3
// i: 4
复制代码
// 或者采起传参的方式,使用了闭包
for (var i = 0; i < 5; i++) {
(function(j){
setTimeout(function() {
console.log('i: ',j);
}, 1000);
})(i);
}
console.log(i);
// 输出
// i is not defined
// i: 0
// i: 1
// i: 2
// i: 3
// i: 4
复制代码
// setTimeout 的第三个参数
for (var i = 0; i < 5; i++) {
setTimeout(function timer(j) {
console.log('i: ', j);
}, 1000, i);
}
console.log(i);
// 输出
// i is not defined
// i: 0
// i: 1
// i: 2
// i: 3
// i: 4
复制代码