假设我们想设计一个计数器,每次调用方法 add()
,计数器就加1。
如果使用局部变量,如下所示。实际上并不起作用,因为局部变量的作用域为函数本身。
function add() {
var count = 0;
count++;
}
add(); // 每次调用都是1
add(); // 每次调用都是1
add(); // 每次调用都是1
如果使用全局变量,如下所示。可以实现计数器功能,但是变量 count
也会被其他函数访问修改,并不安全。
var count = 0;
function add() {
count++;
}
add();
add();
add();
console.log(count); // 3
JavaScript Closures
A closure is a function having access to the parent scope, even after the parent function has closed.
closure 是一个函数,该函数可以访问上一层的 Scope,即使 parent 函数已经结束。
在下面的代码中:
- 变量
add
是一个 self-invoking 函数的返回值 - 该 self-invoking 函数只执行一次,设置
count
为 0,返回一个函数表达式 function expression - 因此
add
实际上是一个函数,并且可以访问上一层 Scope 中的变量count
- 这就是所谓的 closure。它使得函数可以有一个 private 私有变量
count
,该变量count
只能通过add()
方法访问。
var add = (function () {
var count = 0;
return function () { count++; return count; }
})(); // self-invoking 函数
console.log(add()); // 1
console.log(add()); // 2
console.log(add()); // 3
以上代码等同于如下代码:但是此处的 count
为全局变量,可能会被其他函数修改,不安全。
var count = 0;
var add = function () { count++; return count; };
console.log(add()); // 1
console.log(add()); // 2
console.log(add()); // 3
一个常见面试题
for(var i = 1; i <= 5; i++) { // Global Scope i
setTimeout(function() {
console.log(i);
}, i * 1000);
}
打印出 6 6 6 6 6
for(var i = 1; i <= 5; i++) {
let j = i; // Block Scope j
setTimeout(function() {
console.log(j);
}, i * 1000);
}
打印出 1 2 3 4 5