闭包
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 中可能导致内存泄露. 可以在退出函数之前, 将不再使用的局部变量全部删除.