JavaScript 闭包实用指南

通过深入研究高级概念之一:闭包,更好地理解 JavaScript 代码如何工作和执行。
65 位读者喜欢这篇文章。
Woman programming

WOCinTech Chat。由 Opensource.com 修改。CC BY-SA 4.0

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();

这是此代码的执行上下文: 

闭包在每次创建函数时(在函数创建时)都会被创建。每个闭包都有三个作用域

  • 局部作用域(自身作用域)
  • 外部函数作用域
  • 全局作用域

我将稍微修改上面的代码以演示闭包

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

资源记录(resourceRecord1resourceRecord2)彼此独立。每个闭包通过其自身的闭包引用不同版本的 resourceNameresourceAddress 变量。您还可以应用特定规则来规定如何处理私有变量——我添加了一个关于谁可以修改 resourceName 的检查。

使用闭包

理解闭包非常重要,因为它能够更深入地了解变量和函数如何相互关联,以及 JavaScript 代码如何工作和执行。

接下来阅读
标签
User profile image.
Nimisha Mukherjee 是 Red Hat 的一名工程经理。她的团队致力于为在 Red Hat OpenShift 上构建云原生应用程序提供简化的开发者体验。总体而言,她在交付前沿 Web 应用程序方面拥有 18 年以上的经验。她一直喜欢构建提供差异化用户体验的用户界面。

评论已关闭。

Creative Commons 许可协议本作品根据知识共享署名-相同方式共享 4.0 国际许可协议获得许可。
© . All rights reserved.