通过深入了解 JavaScript 的高级概念之一:闭包,更好地理解 JavaScript 代码的工作和执行方式。
在《JavaScript 如此受欢迎的 4 个原因》中,我提到了一些高级 JavaScript 概念。在本文中,我将深入探讨其中的一个概念:闭包closure。
根据 Mozilla 开发者网络(MDN),“闭包是将一个函数和对其周围的状态(词法环境)的引用捆绑在一起(封闭)的组合。”简而言之,这意味着在一个函数内部的函数可以访问其外部(父)函数的变量。
为了更好地理解闭包,可以看看作用域及其执行上下文。
下面是一个简单的代码片段:
复制
var hello = "Hello";
function sayHelloWorld() {
var world = "World";
function wish() {
var year = "2021";
console.log(hello + " " + world + " "+ year);
}
wish();
}
sayHelloWorld();
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
下面是这段代码的执行上下文:
JS 代码的执行上下文
每次创建函数时(在函数创建阶段)都会创建闭包。每个闭包有三个作用域。
本地作用域(自己的作用域)
外部函数范围
全局范围
我稍微修改一下上面的代码来演示一下闭包:
复制
var hello = "Hello";
var sayHelloWorld = function() {
var world = "World";
function wish() {
var year = "2021";
console.log(hello + " " + world + " "+ year);
}
return wish;
}
var callFunc = sayHelloWorld();
callFunc();
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
内部函数 wish()
在执行之前就从外部函数返回。这是因为 JavaScript 中的函数形成了闭包。
当 sayHelloWorld
运行时,callFunc
持有对函数 wish
的引用。
wish
保持对其周围(词法)环境的引用,其中存在变量 world
。
本身,JavaScript 不支持创建私有变量和方法。闭包的一个常见和实用的用途是模拟私有变量和方法,并允许数据隐私。在闭包范围内定义的方法是有特权的。
这个代码片段捕捉了 JavaScript 中闭包的常用编写和使用方式:
复制
var resourceRecord = function(myName, myAddress) {
var resourceName = myName;
var resourceAddress = myAddress;
var accessRight = "HR";
return {
changeName: function(updateName, privilege) {
// only HR can change the name
if (privilege === accessRight ) {
resourceName = updateName;
return true;
} else {
return false;
}
},
changeAddress: function(newAddress) {
// any associate can change the address
resourceAddress = newAddress;
},
showResourceDetail: function() {
console.log ("Name:" + resourceName + " ; Address:" + resourceAddress);
}
}
}
// Create first record
var resourceRecord1 = resourceRecord("Perry","Office");
// Create second record
var resourceRecord2 = resourceRecord("Emma","Office");
// Change the address on the first record
resourceRecord1.changeAddress("Home");
resourceRecord1.changeName("Perry Berry", "Associate"); // Output is false as only an HR can change the name
resourceRecord2.changeName("Emma Freeman", "HR"); // Output is true as HR changes the name
resourceRecord1.showResourceDetail(); // Output - Name:Perry ; Address:Home
resourceRecord2.showResourceDetail(); // Output - Name:Emma Freeman ; Address:Office
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
资源记录(resourceRecord1
和 resourceRecord2
)相互独立。每个闭包通过自己的闭包引用不同版本的 resourceName
和 resourceAddress
变量。你也可以应用特定的规则来处理私有变量,我添加了一个谁可以修改 resourceName
的检查。
理解闭包是很重要的,因为它可以更深入地了解变量和函数之间的关系,以及 JavaScript 代码如何工作和执行。