简单语言的javascript封闭和一个实际的实际示例

    科技2025-02-19  16

    什么是JavaScript闭包? (What are JavaScript closures?)

    It is a JavaScript feature that allows a function to access its outer function scope. Sounds complicated?

    它是一种JavaScript功能,它允许函数访问其外部函数范围。 听起来复杂吗?

    We can use this feature when we have nested functions like this:

    当我们具有如下嵌套函数时,可以使用此功能:

    A simple example of closures 闭包的简单例子

    As you can see the function sayAge has access to the variable age which is in the outer function scope. This is a special feature of JavaScript and we can use it in some situations that I will explain.

    如您所见, sayAge函数可以访问外部函数范围内的变量age 。 这是JavaScript的一项特殊功能,在某些情况下,我们可以使用它。

    闭包的常见技巧 (A common trick with closures)

    If we return a function from another one we can mutate the outer function variables by using the closure feature. For example:

    如果我们从另一个函数返回一个函数,则可以使用闭包功能对外部函数变量进行突变。 例如:

    Changing the outer function’s variable 更改外部函数的变量

    JavaScript closures are as simple as this example but I didn’t understand them till I found a practical usage.

    JavaScript闭包与此示例一样简单,但是直到找到实际用法后,我才了解它们。

    使用JavaScript闭包实现私有变量 (Implementing private variables by using JavaScript Closures)

    We can use this feature to implement private methods inside a JavaScript function:

    我们可以使用此功能在JavaScript函数中实现私有方法:

    Implementing a private variable using Closures 使用闭包实现私有变量

    As we can see setAge has access to privateAge and it can alter this variable. We returned three methods: increment , decrement and value and the user cannot assign something directly to privateAge .

    如我们所见, setAge可以访问privateAge ,并且可以更改此变量。 我们返回了三种方法: increment , decrement和value ,用户无法直接将某些东西分配给privateAge 。

    实际示例 (Practical real-world example)

    I used a few things in this example but please do not get too bogged down. This example is a simple typescript express app that is going to connect to a database(MongoDB) and execute a query.

    在此示例中,我使用了一些内容,但请不要陷入困境。 这个例子是一个简单的打字稿表达应用程序,它将连接到数据库(MongoDB)并执行查询。

    If you want to use this example on your local machine follow these steps:

    如果要在本地计算机上使用此示例,请执行以下步骤:

    You need a MongoDB server(The default port is set to 27022 in this project).

    您需要一台MongoDB服务器(此项目中的默认端口设置为27022)。 Run these commands:

    运行以下命令: git clone https://github.com/pshaddel/js-closure-example.gitcd js-closure-examplenpm installnpm run dev import express from 'express'; import users from './users'; const app: express.Application = express(); app.use(users); app.get('/ping', function (req: express.Request, res: express.Response) { res.send('pong...'); }); app.listen(3000, function () { console.log('App is listening on port 3000!'); });

    We have two routes: one for testing /ping which returns pong in response and the other one is users.

    我们有两种方法:一种用于测试/ping并返回pong作为响应,另一种是users 。

    In this example, I didn’t use any service or controller for simplicity. Let’s see what is inside the users.ts and connection.ts :

    在此示例中,为简单起见,我没有使用任何服务或控制器。 让我们看看users.ts和connection.ts内部的users.ts :

    import express from 'express'; import getDBClient from './connection'; import {Db} from 'mongodb'; const router = express.Router(); router.get('/users', async (req: express.Request, res: express.Response)=> { const connection:Db = await getDBClient(); const result = await connection.collection('users').find({ }).toArray() res.json(result) }) export default router;

    On every get request to /users we want to execute a find query in the MongoDB database. Now a common problem is that we don’t want to create a new connection on each request. What we want is to use one instance of connection and there are two ways(at least I know two ways :)). one of them is using Singleton pattern and classes in typescript and the other one is JavaScript Closure.

    在对/users每个get请求中,我们要在MongoDB数据库中执行一个find查询。 现在常见的问题是我们不想在每个请求上创建一个新的连接。 我们想要的是使用一种连接实例,并且有两种方式(至少我知道两种方式:))。 其中之一是在打字稿中使用Singleton模式和类,另一个是JavaScript Closure。

    Now let’s look at the implementation of connection which returns a function named getDBClient :

    现在让我们看一下连接的实现,它返回一个名为getDBClient的函数:

    import { MongoClient, MongoError, Db } from 'mongodb'; const url = 'mongodb://localhost:27022'; const dbName = 'myproject'; function connection() { let databaseClient:Db|null = null; return function getDBClient () { return new Promise<Db>((resolve, reject)=> { if(databaseClient) { console.log('using previous instance') resolve(databaseClient); } else MongoClient.connect(url, function(err:MongoError, client:MongoClient) { if (err) reject(JSON.stringify(err)); console.log("Connected - Client Created"); databaseClient = client.db(dbName); resolve(databaseClient); }); }) } } export default connection();

    getDBClient is the function inside this file which has access to the outer function scope. So getDBClient has access to databaseClient variable. Look at line 9: if the databaseClient variable is not null we are going to return the client instance and otherwise, we’re going to create a new client. We used closure to mutate an outer function variable.

    getDBClient是此文件中的函数,可以访问外部函数范围。 因此, getDBClient可以访问databaseClient变量。 看第9行:如果databaseClient变量不为null,我们将返回client实例,否则,我们将创建一个新客户端。 我们使用闭包来变异外部函数变量。

    Now no matter how many times we call this API, the code will not create a new connection to the database.

    现在,无论我们调用此API多少次,该代码都不会创建与数据库的新连接。

    Use this command to send request if you are using Linux or Mac OS:

    如果您使用的是Linux或Mac OS,请使用以下命令发送请求:

    curl http://localhost:3000/users Calling the API multiple times 多次调用API

    As we can see the first time we created a connection to the database: Connected — Client Created and after that each time we needed a connection the code returned the previous instance of database client and logs: using previous instance (connection.ts).

    正如我们第一次看到的那样,我们创建了到数据库的连接: Connected — Client Created ,此后每次需要连接时,代码都using previous instance (connection.ts)返回数据库客户端和日志的using previous instance 。

    翻译自: https://medium.com/weekly-webtips/javascript-closure-in-plain-language-and-one-practical-real-world-example-d0dab81c4a05

    相关资源:四史答题软件安装包exe
    Processed: 0.011, SQL: 8