Why You Need JavaScript Closure

从头了解为什么你需要 JavaScript 闭包

从头说起

闭包可以让你在函数内获得函数外作用域的变量

但这么说很难理解,什么是作用域?为了更好地了解闭包,让我们从头说起。通常在函数内会使用两种方法来使用变量:

  • 方法 A:将变量作为参数传入函数内
  • 方法 B:在函数内定义一个变量
// 方法 A
function add(a, b) {
return a + b;
}
// 方法 B
function sayHello() {
const greeting = '你好';
return greeting;
}

但如果函数外想要访问函数内的变量是不行的,这是因为函数会创建一个新的作用域,让变量只能在函数内使用。

function sayHello() {
const greeting = '你好';
return greeting;
}
console.log(greeting); // ReferenceError: greeting is not defined

但如果直接使用函数以外的变量会发生什么事?是可行的!这是因为前面提到的:「闭包可以让你在函数内获得函数外作用域的变量」,闭包只是一种形容这种特性的词汇,实际牵涉到 JavaScript 的作用域与底层的运行方式,才造就了闭包这种特性。

const greeting = '你好';
function sayHello() {
return greeting;
}
console.log(sayHello()); // 仍旧可以打印出 你好

使用 console.dir 打印函数观察结果

具体来说可以用 console.dir() 来观察该函数,会发现 sayHello 函数具备该函数作用域以外的数据,这份数据就算是在 sayHello 函数执行完成后,仍然可以访问到。

什么时候该使用闭包?

函数以外的作用域会持续存在,就算函数已经执行完毕

闭包需要更多的内存空间与运算,因此最好在真正需要的时候才使用这一特性,大多数时候会用于以下几种情况:

形成私有变量

闭包可以让函数内的变量不会被外部函数访问,因此可以用来形成私有变量。

function makeCounter() {
let count = 0; // 外部无法访问到该变量
return function () {
return (count += 1);
};
}
const counter = makeCounter();
console.log(counter()); // 1

模块化

闭包可以用来搭配工厂模式,模块化代码,保存状态。

function makeCounter() {
let count = 0;
return function () {
return (count += 1);
};
}
const counterA = makeCounter();
const counterB = makeCounter();
console.log(counterA()); // 1
console.log(counterA()); // 2
console.log(counterB()); // 1
console.log(counterB()); // 2

参考资料