一、产生闭包的条件
- 函数内返回函数
function a() {
var c = 100;
function b() {
c = 200;
}
return b;
}
- 函数作为参数传入函数中
function b(fn) {
var c = 100;
fn(c);
}
注:正常情况变量在使用完后,会被垃圾回收机制进行释放,内部函数使用外部函数的变量,会延长该变量的生命周期,由于不知未来会不会再使用该变量,所以不会触发垃圾回收机制(不是内存泄漏)。
二、使用闭包的场景
- 为多个dom元素添加点击事件
<!DOCTYPE html>
<html>
<head>
<title>为多个dom元素添加点击事件</title>
</head>
<body>
<button>点击</button>
<button>点击</button>
<button>点击</button>
<button>点击</button>
<button>点击</button>
<script>
var btns = document.getElementsByTagName('p');
// 无论点击哪个按钮,打印出来的都是5
// 原因:变量i为全局变量,点击事件为异步操作,当初发点击回调时,for循环已经执行完成,此时i=5
for(var i = 0; i < 5; i++) {
btns[i].click = () => {
console.log(i);
}
}
// 依次点击按钮,打印0, 1, 2, 3, 4
// es5中有全局作用域和函数作用域,立即执行函数形成函数作用域,点击回调函数打印的是当时传入立即执行函数的i值,并不是全局变量i
for(var i = 0; i < 5; i++) {
(function () {
btns[i].click = () => {
console.log(i);
}
})(i)
}
// 依次点击按钮,打印0, 1, 2, 3, 4
// 原因:es6新增了块级作用域,for循环中通过let定义i,每次循环都会在()和{}中形成块级作用域,其中()为父作用域,{}为子作用域,所以子作用域的i为其父作用域中的i
for(let i = 0; i < 5; i++) {
btns[i].click = () => {
console.log(i);
}
}
</script>
</body>
</html>