在 JavaScript 为何如此流行的 4 个原因 中,我提到了几个高级 JavaScript 概念。在本文中,我将深入探讨其中一个概念:闭包。
根据 Mozilla 开发者网络 (MDN),“闭包是将函数捆绑在一起(封闭)并引用其周围状态(词法环境)的组合。” 简单来说,这意味着一个函数内部的函数可以访问外部(父)函数的变量。
为了更好地理解闭包,请了解作用域及其执行上下文。
这是一个简单的代码片段
var hello = "Hello";
function sayHelloWorld() {
var world = "World";
function wish() {
var year = "2021";
console.log(hello + " " + world + " "+ year);
}
wish();
}
sayHelloWorld();
这是此代码的执行上下文:

(Nimisha Mukherjee,CC BY-SA 4.0)
闭包在每次创建函数时(在函数创建时)都会被创建。每个闭包都有三个作用域
- 局部作用域(自身作用域)
- 外部函数作用域
- 全局作用域
我将稍微修改上面的代码以演示闭包
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();
内部函数 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
资源记录(resourceRecord1
和 resourceRecord2
)彼此独立。每个闭包通过其自身的闭包引用不同版本的 resourceName
和 resourceAddress
变量。您还可以应用特定规则来规定如何处理私有变量——我添加了一个关于谁可以修改 resourceName
的检查。
使用闭包
理解闭包非常重要,因为它能够更深入地了解变量和函数如何相互关联,以及 JavaScript 代码如何工作和执行。
评论已关闭。