JavaScript 闭包实践
JavaScript 闭包

> 
> 通过深入了解 JavaScript 的高级概念之一：闭包，更好地理解 JavaScript 代码的工作和执行方式。
> 
> 
> 


![](/data/attachment/album/202102/21/162941ogyb74z3ahfbfe35.jpg "Woman programming")


在《[JavaScript 如此受欢迎的 4 个原因](/article-12830-1.html)》中，我提到了一些高级 JavaScript 概念。在本文中，我将深入探讨其中的一个概念：<ruby> 闭包 <rt>  closure </rt></ruby>。


根据 [Mozilla 开发者网络](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures)（MDN），“闭包是将一个函数和对其周围的状态（词法环境）的引用捆绑在一起（封闭）的组合。”简而言之，这意味着在一个函数内部的函数可以访问其外部（父）函数的变量。


为了更好地理解闭包，可以看看作用域及其执行上下文。


下面是一个简单的代码片段：



```
var hello = "Hello";

function sayHelloWorld() {
    var world = "World";
    function wish() {
        var year = "2021";
        console.log(hello + " " + world + " "+ year);
    }
    wish();
}
sayHelloWorld();

```

下面是这段代码的执行上下文：


![JS 代码的执行上下文](/data/attachment/album/202102/21/163151d6tma7k3pp2lgz43.png "Execution context for JS code")


每次创建函数时（在函数创建阶段）都会创建闭包。每个闭包有三个作用域。


* 本地作用域（自己的作用域）
* 外部函数范围
* 全局范围


我稍微修改一下上面的代码来演示一下闭包：



```
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 代码如何工作和执行。




---


via: <https://opensource.com/article/21/2/javascript-closures>


作者：[Nimisha Mukherjee](https://opensource.com/users/nimisha) 选题：[lujun9972](https://github.com/lujun9972) 译者：[wxy](https://github.com/wxy) 校对：[wxy](https://github.com/wxy)


本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


OK
In [ 4 reasons why JavaScript is so popular](https://opensource.com/article/20/11/javascript-popular), I touched on a few advanced JavaScript concepts. In this article, I will dive into one of them: closures.

According to [Mozilla Developer Network](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures) (MDN), "A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment)." Simplified, this means that a function inside another function can access the variables from the outer (parent) function.

To better understand closures, take a look at scopes and their execution context.

Here is a simple code snippet:

```
var hello = "Hello";
function sayHelloWorld() {
var world = "World";
function wish() {
var year = "2021";
console.log(hello + " " + world + " "+ year);
}
wish();
}
sayHelloWorld();
```


Here's the execution context for this code:

![Execution context for JS code Execution context for JS code](https://opensource.com/sites/default/files/uploads/execution-context.png)

(Nimisha Mukherjee, CC BY-SA 4.0)

Closures are created every time a function is created (at function-creation time). Every closure has three scopes:

- Local scope (own scope)
- Outer functions scope
- Global scope

I'll modify the above code slightly to demonstrate closure:

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



The inner function `wish()`

is returned from the outer function before it's executed. This happens because functions in JavaScript form **closures**.

`callFunc`

holds a reference to the function`wish`

when`sayHelloWorld`

runs`wish`

maintains a reference to its surrounding (lexical) environment where the variable`world`

exists.

## Private variables and methods

Natively, JavaScript does not support the creation of private variables and methods. A common and practical use of closure is to emulate private variables and methods and allow data privacy. Methods defined within the closure scope are privileged.

This code snippet captures how closures are commonly written and used in 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
```


The resource records (`resourceRecord1`

and `resourceRecord2`

) are independent of one another. Each closure references a different version of the `resourceName`

and `resourceAddress`

variable through its own closure. You can also apply specific rules to how private variables need to be handled—I added a check on who can modify `resourceName`

.

## Use closures

Understanding closure is important, as it enables deeper knowledge of how variables and functions relate to one another and how JavaScript code works and executes.

## Comments are closed.