search
HomeWeb Front-endJS TutorialJavaScript summary sharing closure

This article brings you relevant knowledge about JavaScript, which mainly introduces related issues about closures, including what closures are, why they are designed in this way and how they can be used. Let’s take a look at the relevant content below. I hope it will be helpful to everyone.

JavaScript summary sharing closure

[Related recommendations: JavaScript video tutorial, web front-end]

What is a closure?

For a knowledge point, I have always believed that no matter where you start from, you need to thoroughly understand three questions before you can truly understand this knowledge point, and then practice it in practice in order to be able to claim it. To be mastered. These three questions are: What is

  • ?
  • Why design?
  • Where can it be used?

First answer the question of what closure is. Most people should have read many related articles, and many people have also given their own explanations, so I will first give an explanation that I understand, that is: There are two prerequisite concepts:

  • Closure has been determined during lexical analysis, so it will be related to lexical scope.

  • The prerequisite for the existence of closures is that a programming language needs to support functions as first-class citizens, so it will be related to functions.

So the final conclusion is:

  • The closure is first a structure, and the components of this structure are a function. The lexical scope at
  • is The closure is a structure generated by a function and the function can remember to declare its own lexical scope.
  • Understanding in memory is that when a function is called, The scope chain in the function execution context it generates saves its parent lexical scope, so the parent variable object is referenced due to its existence It will not be destroyed and will reside in memory for its use. This situation is called closure.

The above explanation should be clear to those who have already understood closures, but in fact, if it is for a person who does not know closures at all, it may be completely incomprehensible. What's more, many people actually just remember this definition, but don't really understand the connotation.

So I want to use an analogy that is not necessarily accurate to help understand what closures are. Imagine that you wrote an article and put it on your own server, and cited 3 of your own articles as references. . So at this time, the server environment of an article is similar to a closure.

After being published on the Internet, it will be reprinted on other platforms. If readers on other platforms click on your article and want to continue reading the articles you quoted, they will be accurately redirected. Go to the article on your server.

In this example, this article saves a reference to the server environment in which this article was written. Therefore, no matter where you read the article, the reference article reference remembered in the article will always point to the address in the server. This situation is called using the closure feature.

Maybe the example is still not easy to understand, after all, it is not very accurate. The concept of closure is a bit abstract, and I didn't think of any concrete examples in reality that can be used as a metaphor. If anyone has a better analogy to point out, I'll annotate and describe it.

Why should we design closure?

As for why this is designed, my superficial understanding is because JavaScript is an asynchronous single-threaded language. The biggest problem with asynchronous programming is that when you write a function, the time it is actually called may be at any time later.

This is a big problem for memory management. For normally synchronously executed code, the data required when the function is declared and called still remains in the memory. You can Accessible. Asynchronous code often declares that the context of the function may have been destroyed. By the time it is called, if some external data it requires has been cleared in the memory, this is a big problem.

So the solution for JavaScript is to allow the function to remember the range of data it can obtain before, and all of them are stored in the memory. As long as the function is not recycled by the memory, it itself and what it can remember None of the scopes will be destroyed.

The scope that can be remembered here refers to the lexical scope, which needs to be remembered because it is static.

This is again caused by the static design scope of JavaScript. If it is a dynamic scope, when the function is called, it only needs the environment when it is called, and there is no need to remember its own scope.

So to summarize:

  • Closures are created to solve the problems caused by lexical scope and poor memory management in data acquisition in asynchronous programming.

Classic question

Originally my idea was to explain the closure situation from the lowest level. Later, when I checked various articles, I found that one article was already well written. . That is the underlying operating mechanism of JavaScript closures. I think you can read this explanation first and then read what I write later.

Since there are a lot of articles starting from the following very classic interview question, but no one seems to have really explained it from the bottom level, so I plan to sort out the whole process to understand it. difference.

for (var i = 0; i <p>Basically all people with basic skills can tell at a glance that the output is three 3's. </p><p>Then modify it to output in order. Usually you only need to modify var to let: </p><pre class="brush:php;toolbar:false">for (let i = 0; i <p>In this way, the output is 0, 1, 2. And it is output at the same time, not every time Output once every one second. </p><p>Then the question is, why? </p><p>You can write your own explanation first without reading the following to see if it is the same as what I wrote. </p><h3 id="Let-s-first-discuss-the-situation-where-variable-i-is-var">1. Let’s first discuss the situation where variable i is var. </h3><p>When the code starts executing, the situation in the execution context stack and memory is as follows:
The <code> variable i</code> in the global object and the <code> variable i</code> in the variable environment in the global execution context are the same variable. </p><p><img src="/static/imghwm/default1.png" data-src="https://img.php.cn/upload/article/000/000/067/9a47ad7a4a0d4fc53eb0f94f9afe21af-2.png?x-oss-process=image/resize,p_40" class="lazy" alt="" loading="lazy"></p><p>Then the loop starts. When i = 0, the first timer is thrown into the macro task queue. The content related to macro tasks belongs to the event loop category. For the time being, Just understand that setTimeout will be thrown into the queue and executed later.
At this time, its callback function cb will be created in the heap memory, and [[scope]] will be created when the function is created. In the actual ECMA rules, [[scope]] will point to the parent scope of the function, which is the current The global object (scope is a conceptual thing, and the actual manifestation in memory is a structure that saves data, which may be an object or something else).
However, in the implementation of the V8 engine, it does not actually point to the global object. Instead, it analyzes which variables in the parent scope are used by the function, stores these variables in the Closure, and then points to the scope. Each function has exactly one Closure object. </p><p><img src="/static/imghwm/default1.png" data-src="https://img.php.cn/upload/article/000/000/067/975c7fff2dd731e7167c6f10a9c0768c-3.png?x-oss-process=image/resize,p_40" class="lazy" alt="" loading="lazy"></p><hr><p>Here is the information about where the Closure object can be seen in Chrome:
As you can see, when the bar function is created, it only references the name variable of the parent scope, so only the variable name is stored in the closure object, and the variable age does not exist. <img src="/static/imghwm/default1.png" data-src="https://img.php.cn/upload/article/000/000/067/7597043a638c68edf0ea2bf1903de197-4.png?x-oss-process=image/resize,p_40" class="lazy" alt="" loading="lazy"></p><hr><p>Similarly, i = 1, and i = 2 are the same, and the final result will become: </p><p><img src="/static/imghwm/default1.png" data-src="https://img.php.cn/upload/article/000/000/067/bb636bd0eb31982153af2194f804fc87-5.png?x-oss-process=image/resize,p_40" class="lazy" alt="" loading="lazy"></p><p> Finally, i = 3 because of i, the loop ends, and the global code is executed. The result at this time is: </p><p>Then the execution process of the timer callback function begins.
Start executing the callback function in the first timer, push it into the execution context stack, and execute the output i. However, the variable i cannot be found in the lexical environment and variable environment, so we go to its own [[scope]] and look up. i is found in the Closure object and is equal to 3, and the output result is 3. </p><p><img src="/static/imghwm/default1.png" data-src="https://img.php.cn/upload/article/000/000/067/6f889de25bdd38ac3e03fdd316a95d48-7.png?x-oss-process=image/resize,p_40" class="lazy" alt="" loading="lazy"></p><p>Similarly, the process is the same for the next two timers, and in fact the time when the timer is started is executed immediately in the loop, resulting in the actual three The timing of each function is consistent for 1 second, and the final output result is that three 3's are output almost simultaneously. Instead of outputting 3 after every 1 second interval, of course this is timer-related knowledge. </p><h3 id="strong-Then-discuss-what-actually-changed-after-changing-var-to-let-strong"><strong>2. Then discuss what actually changed after changing var to let</strong></h3><p>When it was first created, the situation shown is:</p><p><img src="/static/imghwm/default1.png" data-src="https://img.php.cn/upload/article/000/000/067/1e098f4f58a6df5b627cef909dd2e3db-8.png?x-oss-process=image/resize,p_40" class="lazy" alt="" loading="lazy"></p><p> After entering the loop body, when i = 0: </p><p><img src="/static/imghwm/default1.png" data-src="https://img.php.cn/upload/article/000/000/067/8b88767eeee8536e539ddc5a2f0f900c-9.png?x-oss-process=image/resize,p_40" class="lazy" alt="" loading="lazy"></p><p> Then enter the situation when i = 1: </p><p><img src="/static/imghwm/default1.png" data-src="https://img.php.cn/upload/article/000/000/067/517141f297095cebe6688741c6e812e6-10.png?x-oss-process=image/resize,p_40" class="lazy" alt="" loading="lazy"></p><p> Finally enters the situation of i = 2, which is basically similar to i = 1: </p><p><img src="/static/imghwm/default1.png" data-src="https://img.php.cn/upload/article/000/000/067/834b61d90ff149757669225acfc00469-11.png?x-oss-process=image/resize,p_40" class="lazy" alt="" loading="lazy"></p><p>Finally i becomes i value 3 , the cycle ends. Start timer work: </p><p><img src="/static/imghwm/default1.png" data-src="https://img.php.cn/upload/article/000/000/067/bb28646fa09ab7792cdbb9033f36eec9-12.png?x-oss-process=image/resize,p_40" class="lazy" alt="" loading="lazy"></p><p>当执行第一个定时器的回调函数时,创建了函数执行上下文,此时执行输出语句i时,会先从自己的词法环境里寻找变量i的值,也就是在 record环境记录里搜索,但是不存在。因而通过自己外部环境引用outer找到原先创建的块级作用域里 i = 0的情况, 输出了i值为0的结果。</p><p>对于之后的定时器也都是一样的情况,原先的块级作用域由于被回调函数所引用到了,因而就产生了闭包的情况,不会在内存中被销毁,而是一直留着。</p><p>等到它们都执行完毕后,最终内存回收会将之全部都销毁。</p><blockquote><p>其实以上画的图并不是很严谨,与实际在内存中的表现肯定是有差异的,但是对于理解闭包在内存里的情况还是不影响的。</p></blockquote><h2 id="闭包能用在哪">闭包能用在哪?</h2><p>首先需要先明确一点,<code>那就是在JavaScript中,只要创建了函数,其实就产生了闭包</code>。这是广义上的闭包,因为在全局作用域下声明的函数,也会记着全局作用域。而不是只有在函数内部声明的函数才叫做闭包。</p><p>通常意义上所讨论的闭包,是<code>使用了闭包的特性</code>。</p><h3 id="strong-函数作为返回值-strong"><strong>1. 函数作为返回值</strong></h3><pre class="brush:php;toolbar:false">let a = 1function outer() {  let a = 2

  function inside() {
    a += 1
    console.log(a)
  }  return inside
}const foo = outer()foo()

此处outer函数调用完时,返回了一个inside函数,在执行上下文栈中表示的既是outer函数执行上下文被销毁,但有一个返回值是一个函数。 该函数在内存中创建了一个空间,其[[scope]]指向着outer函数的作用域。因而outer函数的环境不会被销毁。

当foo函数开始调用时,调用的就是inside函数,所以它在执行时,先询问自身作用域是否存在变量a, 不存在则向上询问自己的父作用域outer,存在变量a且值为2,最终输出3。

2. 函数作为参数

var name = 'xavier'function foo() {  var name = 'parker'
  function bar() {    console.log(name)
  } console.log(name)  return bar
}function baz(fn) {  var name = 'coin'
  fn()
}baz(foo())baz(foo)

对于第一个baz函数调用,输出的结果为两个'parker'。 对于第二个baz函数的调用,输出为一个'parker'。

具体的理解其实跟上面一致,只要函数被其他函数调用,都会存在闭包。

3. 私有属性

闭包可以实现对于一些属性的隐藏,外部只能获取到属性,但是无法对属性进行操作。

function foo(name) {  let _name = name  return {    get: function() {      return _name
    }
  }
}let obj = foo('xavier')
obj.get()

4. 高阶函数,科里化,节流防抖等

对于一些需要存在状态的函数,都是使用到了闭包的特性。

// 节流function throttle(fn, timeout) {  let timer = null
  return function (...arg) {    if(timer) return
    timer = setTimeout(() => {
    fn.apply(this, arg)
    timer = null
    }, timeout)
  }
}// 防抖function debounce(fn, timeout){  let timer = null
  return function(...arg){    clearTimeout(timer)
    timer = setTimeout(() => {
      fn.apply(this, arg)
    }, timeout)
  }
}

5. 模块化

在没有模块之前,对于不同地方声明的变量,可能会产生冲突。而闭包能够创造出一个封闭的私有空间,为模块化提供了可能性。 可以使用IIFE+闭包实现模块。

var moduleA = (function (global, doc) {  var methodA = function() {};  var dataA = {};  return {    methodA: methodA,    dataA: dataA
  };
})(this, document);

【相关推荐:JavaScript视频教程web前端

The above is the detailed content of JavaScript summary sharing closure. For more information, please follow other related articles on the PHP Chinese website!

Statement
This article is reproduced at:掘金. If there is any infringement, please contact admin@php.cn delete
JavaScript and the Web: Core Functionality and Use CasesJavaScript and the Web: Core Functionality and Use CasesApr 18, 2025 am 12:19 AM

The main uses of JavaScript in web development include client interaction, form verification and asynchronous communication. 1) Dynamic content update and user interaction through DOM operations; 2) Client verification is carried out before the user submits data to improve the user experience; 3) Refreshless communication with the server is achieved through AJAX technology.

Understanding the JavaScript Engine: Implementation DetailsUnderstanding the JavaScript Engine: Implementation DetailsApr 17, 2025 am 12:05 AM

Understanding how JavaScript engine works internally is important to developers because it helps write more efficient code and understand performance bottlenecks and optimization strategies. 1) The engine's workflow includes three stages: parsing, compiling and execution; 2) During the execution process, the engine will perform dynamic optimization, such as inline cache and hidden classes; 3) Best practices include avoiding global variables, optimizing loops, using const and lets, and avoiding excessive use of closures.

Python vs. JavaScript: The Learning Curve and Ease of UsePython vs. JavaScript: The Learning Curve and Ease of UseApr 16, 2025 am 12:12 AM

Python is more suitable for beginners, with a smooth learning curve and concise syntax; JavaScript is suitable for front-end development, with a steep learning curve and flexible syntax. 1. Python syntax is intuitive and suitable for data science and back-end development. 2. JavaScript is flexible and widely used in front-end and server-side programming.

Python vs. JavaScript: Community, Libraries, and ResourcesPython vs. JavaScript: Community, Libraries, and ResourcesApr 15, 2025 am 12:16 AM

Python and JavaScript have their own advantages and disadvantages in terms of community, libraries and resources. 1) The Python community is friendly and suitable for beginners, but the front-end development resources are not as rich as JavaScript. 2) Python is powerful in data science and machine learning libraries, while JavaScript is better in front-end development libraries and frameworks. 3) Both have rich learning resources, but Python is suitable for starting with official documents, while JavaScript is better with MDNWebDocs. The choice should be based on project needs and personal interests.

From C/C   to JavaScript: How It All WorksFrom C/C to JavaScript: How It All WorksApr 14, 2025 am 12:05 AM

The shift from C/C to JavaScript requires adapting to dynamic typing, garbage collection and asynchronous programming. 1) C/C is a statically typed language that requires manual memory management, while JavaScript is dynamically typed and garbage collection is automatically processed. 2) C/C needs to be compiled into machine code, while JavaScript is an interpreted language. 3) JavaScript introduces concepts such as closures, prototype chains and Promise, which enhances flexibility and asynchronous programming capabilities.

JavaScript Engines: Comparing ImplementationsJavaScript Engines: Comparing ImplementationsApr 13, 2025 am 12:05 AM

Different JavaScript engines have different effects when parsing and executing JavaScript code, because the implementation principles and optimization strategies of each engine differ. 1. Lexical analysis: convert source code into lexical unit. 2. Grammar analysis: Generate an abstract syntax tree. 3. Optimization and compilation: Generate machine code through the JIT compiler. 4. Execute: Run the machine code. V8 engine optimizes through instant compilation and hidden class, SpiderMonkey uses a type inference system, resulting in different performance performance on the same code.

Beyond the Browser: JavaScript in the Real WorldBeyond the Browser: JavaScript in the Real WorldApr 12, 2025 am 12:06 AM

JavaScript's applications in the real world include server-side programming, mobile application development and Internet of Things control: 1. Server-side programming is realized through Node.js, suitable for high concurrent request processing. 2. Mobile application development is carried out through ReactNative and supports cross-platform deployment. 3. Used for IoT device control through Johnny-Five library, suitable for hardware interaction.

Building a Multi-Tenant SaaS Application with Next.js (Backend Integration)Building a Multi-Tenant SaaS Application with Next.js (Backend Integration)Apr 11, 2025 am 08:23 AM

I built a functional multi-tenant SaaS application (an EdTech app) with your everyday tech tool and you can do the same. First, what’s a multi-tenant SaaS application? Multi-tenant SaaS applications let you serve multiple customers from a sing

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
1 months agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
1 months agoBy尊渡假赌尊渡假赌尊渡假赌
Will R.E.P.O. Have Crossplay?
1 months agoBy尊渡假赌尊渡假赌尊渡假赌

Hot Tools

WebStorm Mac version

WebStorm Mac version

Useful JavaScript development tools

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

Atom editor mac version download

Atom editor mac version download

The most popular open source editor

DVWA

DVWA

Damn Vulnerable Web App (DVWA) is a PHP/MySQL web application that is very vulnerable. Its main goals are to be an aid for security professionals to test their skills and tools in a legal environment, to help web developers better understand the process of securing web applications, and to help teachers/students teach/learn in a classroom environment Web application security. The goal of DVWA is to practice some of the most common web vulnerabilities through a simple and straightforward interface, with varying degrees of difficulty. Please note that this software

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser is a secure browser environment for taking online exams securely. This software turns any computer into a secure workstation. It controls access to any utility and prevents students from using unauthorized resources.