Appearance
闭包
是什么
在 JavaScript 中,函数可以作为参数和返回值, 当一个内嵌函数的引用环境发生了改变,但仍需要访问原来的引用环境, 就必须以某种方式将内嵌函数的引用环境和它捆绑在一起,这个整体就称为函数的闭包(closure)。
很多文章是这样介绍闭包的:从某个函数返回的函数所记住的上下文信息。
但实际上闭包不只是在函数被返回时才创建的。
不返回函数,但是有闭包的效果
function f(fn, x) {
if (x < 1) {
f(g, 1);
} else {
fn();
}
function g() {
console.log(x);
}
}
function h() {}
f(h, 0); // 输出结果 -> 0 而不是 1
什么是内嵌函数
function test() {
const a = 1;
return function closure() {
console.log(a);
};
}
在这种情况下,我们将函数 closure 称为内嵌函数,而 test 称为外套函数。
经典例子
var list = document.createElement('ul');
for (var i = 1; i <= 5; i++) {
var item = document.createElement('li');
item.appendChild(document.createTextNode('Item ' + i));
item.onclick = function (e) {
console.log('Item ' + i + ' is clicked.');
};
list.appendChild(item);
}
document.body.appendChild(list);
这段代码的原意是想单击每个li元素时,打印它们的编号,但实际上,无论单击哪一个li,打印输出的都是Item 6 is clicked.。
使用闭包
item.onclick = (function (j) {
return function (e) {
console.log('Item ' + j + ' is clicked.');
};
})(i);
使用 let
for (let i = 1; i <= 5; i++) {
// 省略
}
题外话
类似于这种需求,我们可以使用事件委托的机制做一个优化,仅仅给父元素添加一个事件监听器,而不是给每个子元素添加事件监听器。
参考资料
- 《JavaScript 函数式编程思想》潘俊