Skip to content

闭包

什么是闭包?

闭包允许函数访问并操作函数外的变量。只要变量或者函数存在于声明函数时的作用域内,闭包即可使函数能够访问这些变量和函数。

闭包的应用场景

1. 创建私有变量

javascript
function person() {
  let money = 0;
  return {
    getMoney() {
      return money;
    }
    work() {
      money = money + 1000;
    }
  }
}

const p1 = new Person();
// 无法直接访问私有属性 money
console.log(p1.money) // -> undefined;
// 通过 getMoney 方法可以访问到私有变量 money
console.log(p1.getMoney()) // -> 0;

2. 回调函数

一个经典的代码示例

javascript
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.

解决方案 1:使用闭包

javascript
item.onclick = (function (j) {
  return function (e) {
    console.log('Item ' + j + ' is clicked.');
  };
})(i);

解决方案 2:使用 let

javascript
for (let i = 1; i <= 5; i++) {
  // 省略
}

题外话

类似于这种需求,我们可以使用事件委托的机制做一个优化,仅仅给父元素添加一个事件监听器,而不是给每个子元素添加事件监听器。

参考资料

  • 《JavaScript 函数式编程思想》潘俊
  • 《JavaScript 忍者秘籍》