上一章JavaScript教程请查看:JS函数提升和变量提升
在本教程中,你将了解什么是JavaScript闭包以及它是如何工作的。
了解JavaScript闭包
在JavaScript函数一章中,你已经了解到,在JavaScript中,变量的作用域可以是全局的,也可以是局部的,在ES6中,你还可以使用let关键字创建块范围的变量。
全局变量可以在程序的任何地方访问和操作,而局部变量只能由它们声明的函数访问和操作。
但是,在某些情况下,你希望一个变量在整个脚本中都可用,但又不希望代码的任何部分都能够意外地更改其值。
让我们看看会发生什么,如果你试图实现这个使用全局变量:
// 全局变量
var counter = 0;
// 一个专门用来操作'counter'变量的函数
function makeCounter() {
return counter += 1;
}
// 调用函数
makeCounter();
console.log(counter); // : 1
makeCounter();
console.log(counter); // : 2
// 试图从外部操作'counter'变量
counter = 10;
console.log(counter); // : 10
正如你在上面的示例中所看到的,计数器变量的值可以在程序中的任何位置进行更改,而无需调用makeCounter()函数(第17行)。
现在,让我们尝试用局部变量实现同样的事情,看看会发生什么:
function makeCounter() {
// 本地变量
var counter = 0;
// 操作'counter'变量
return counter += 1;
}
// 调用函数
console.log(makeCounter()); // : 1
console.log(makeCounter()); // : 1
在这种情况下,counter变量不能从外部操作,因为它是本地makeCounter()函数的变量,但是后续调用函数之后它的值也不会增加,因为每次我们调用这个函数重置计数器变量的值,你可以清楚地看到在上面的例子中(第11行)。JavaScript闭包可以解决我们的问题。
function makeCounter() {
var counter = 0;
// 内部函数
function make() {
counter += 1;
return counter;
}
return make;
}
/* 执行makeCounter()函数并将返回的值存储在myCounter变量中 */
var myCounter = makeCounter();
console.log(myCounter()); // : 1
console.log(myCounter()); // : 2
在上面的例子中可以看到,内部函数make()是从外部函数makeCounter()返回的。因此,myCounter的值是内部的make()函数(第14行),调用myCounter可以有效地调用make()。在JavaScript中,函数可以赋值给变量,作为参数传递给其他函数,可以嵌套在其他函数中。
你还会注意到,内部函数make()仍然能够访问外部函数中定义的计数器变量的值,即使makeCounter()函数已经完成执行(第14行)。这是因为JavaScript表单闭包中的函数。闭包在内部存储对其外部变量的引用,并且可以访问和更新它们的值。
在上面的例子中,make()函数是一个闭包,它的代码引用外部变量计数器。这意味着无论何时调用make()函数,其中的代码都能够访问和更新计数器变量,因为它存储在闭包中。
最后,由于外部函数已经完成执行,所以代码的其他部分不能访问或操作计数器变量。只有内部函数可以独占访问它。
前面的例子也可以用匿名函数表达式来写,就像这样:
// 匿名函数表达式
var myCounter = (function() {
var counter = 0;
// 嵌套的匿名函数
return function() {
counter += 1;
return counter;
}
})();
console.log(myCounter()); // : 1
console.log(myCounter()); // : 2
提示:在JavaScript中,所有函数都可以访问全局作用域,以及它们上面的作用域。由于JavaScript支持嵌套函数,这通常意味着嵌套函数可以访问更高范围内声明的任何值,包括其父函数的范围。
注意:只要应用程序(即web页面)存在,全局变量就存在。然而,局部变量的生命周期很短,它们是在调用函数时创建的,在函数执行完后立即销毁。
创建Getter和Setter函数
在这里,我们将创建一个变量secret,并使用闭包保护它不被外部代码直接操作。我们还将创建getter和setter函数来获取和设置它的值。
此外,setter函数还将快速检查指定的值是否是数字,如果不是,则不会更改变量值。
var getValue, setValue;
// 自执行函数
(function() {
var secret = 0;
// Getter函数
getValue = function() {
return secret;
};
// Setter函数
setValue = function(x) {
if(typeof x === "number") {
secret = x;
}
};
}());
// 调用函数
getValue(); // : 0
setValue(10);
getValue(); // : 10
setValue(null);
getValue(); // : 10
提示:自动执行的函数也称为立即调用的函数表达式(IIFE)、立即执行的函数或自动执行的匿名函数。
评论前必须登录!
注册