Contents

闭包

一个函数和对其周围状态 (lexical environment, 词法环境) 的引用捆绑在一起 (或者说函数被引用包围) , 这样的组合就是闭包 (closure).

也就是说, 闭包让你可以在一个内层函数中访问到其外层函数的作用域. 在 JavaScript 中, 每当创建一个函数, 闭包就会在函数创建的同时被创建出来.

对于变量作用域的理解

要理解闭包, 首先必须理解 Javascript 特殊的变量作用域.

变量的作用域无非就是两种: 全局变量和局部变量.

函数内部可以直接读取全局变量:

const n = 999;
function f1() {
  console.log(n);
}
f1(); // 999

而 JavaScript 中的函数运行在他们被定义的作用域里, 而不是他们被执行的作用域里

var 变量提升导致的问题, 尽量避免使用 var

var n = 999;
function f1() {
  console.log('2 ->', n); // undefined
  var n = 666;
  console.log('3 ->', n); // 666
}
console.log('1 ->', n); // 999

f1();

实用技巧

目前闭包被当成函数的高阶技术来使用, 也具有较强的数据安全性, 常见的应用有柯里化(Currying)防抖与节流等.

我们来做一个简单的实例看看:

简单的实例

现在我们来实现一个能够切换背景颜色的选项栏

HTML 部分是一个简单的选项栏

<ul id="selectBGCBar">
  <li>#ddd</li>
  <li>#fff</li>
  <li>#999</li>
</ul>

现在需要注册切换背景颜色的事件, 我们可以使用闭包来完成切换背景颜色的部分

setBGC 函数返回了一个函数, 它具有访问 setBGC 的参数 el 的能力

function setBGC(el) {
  return function () {
    el.style.backgroundColor = el.textContent;
  };
}
const elms = document.querySelectorAll('#selectBGCBar > li');
if (elms) {
  elms.forEach(el => el.addEventListener('click', setBGC(el)));
}

使用闭包的注意点

由于闭包会使得函数中的变量都被保存在内存中, 内存消耗很大, 所以不能滥用闭包, 否则会造成严重的性能问题, 且在 IE 中可能导致内存泄露. 可以在退出函数之前, 将不再使用的局部变量全部删除.

参考链接

闭包 - MDN

学习 Javascript 闭包(Closure)