Home Web Front-end JS Tutorial Closures in JavaScript

Closures in JavaScript

Mar 07, 2018 pm 02:08 PM
javascript js Closure

Closure is just one or two sentences that anyone can recite. But closure is the kind of question that beginners may encounter eight times out of ten interviews. If they can't answer it, they will be given a proposition, and if they can answer it, they won't get any points. In order to prevent our front-end development from getting started and giving up, let me talk about what I think is closure in JS.

What is a closure

A closure creates a lexical scope. After the variables in this scope are referenced, they can be used in this lexical scope. Free access outside the domain is a combination of a function and the lexical environment in which the function is declared.

There is another way of saying that a closure is a function that references a free variable. This free variable exists with the function, even if it is separated. The environment in which it was created. So you often see that a closure is a function bound to a context, and that's probably what it means. Once you understand it, you will realize that it is actually a very simple thing and not very profound.

In the following introduction, I prefer the explanation that closure is a combination of a function and the lexical environment in which the function is declared, so I will also elaborate based on this explanation.

Closure is actually a concept in computer science and is not unique to JS. The concept of closure appeared in the 1960s, and the earliest programming language to implement closure was Scheme. (Don’t ask me what Scheme is, I don’t know if you ask me. This paragraph was copied from Wiki.) After that, closures were widely used in functional programming languages.

Closures in JS

Now, I’m going to use my ultimate trick, to create a closure with my bare hands.

function sayHello(name) {
  let str = `Hello,${name}`;
  function say() {
    console.log(str);
  }
  return say;
}

let myHello = sayHello('abby');
myHello(); // Hello,abby
Copy after login

The above code actually forms a closure. The function say defined in the sayHello function and the lexical environment in which it is declared form a closure because it references sayHello. Define a variable str, and return the say function, so that the variable str defined in it can be accessed outside the sayHello function, as if the say function is bound to this variable.

Seeing this, you may wonder why this variable can still be accessed externally, because in some languages, it is generally believed that the local variables of a function can only be accessed during the execution of the function. Speaking of which, I have to talk about the execution environment. Friends who don’t know much about it may first read my article: Execution Context You Don’t Know. In fact, when the code let myHello = sayHello('abby'); is executed, the execution environment of sayHello() is supposed to be destroyed, but it is not here. The reason is because sayHello() returns a function. In this function The str refers to the external variable str. If it is destroyed, it will not be found. Therefore, the execution environment of the sayHello() function will always be in the memory, so there will be closures that will increase the memory overhead such as balabala.

In fact, when it comes to this, closure should be finished, but there may be many things that make you confused, so let’s continue to talk about a few examples!

For example

Example 1: Closures do not necessarily need to return a function

Although common closures Packages all return a function, but closures do not necessarily have to return. Returning a function is just to access a variable outside the scope. We can also do it in another way, such as:

let say;
function sayHello(name) {
  let str = `Hello,${name}`;
  say = function() {
    console.log(str);
  }
}
let myHello = sayHello('abby');
say(); // Hello,abby
Copy after login

In this example, say and the lexical environment in which it is declared actually form a closure, and its scope holds a reference to the str variable defined in the sayHello function, so it can also be used in str Access a variable outside the scope in which it is defined. Just figure out the nature of closures.

But in JS, the most common way to form a closure is to nest another function inside a function, and the other function holds the variables defined in the parent scope.

Example 2: The same calling function generates the same closure environment, and all functions declared in it also have references to the free variables in this environment.

This sentence sounds confusing, but in fact, I will give you a very simple example.

let get, up, down
function setUp() {
  let number = 20
  get = function() {
    console.log(number);
  }
  up = function() {
    number += 3
  }
  down = function() {
    number -=2;
  }
}
setUp();
get(); // 20
up();
down();
get(); // 21
Copy after login

In this example, we use the setUp function to generate a closure environment. The three functions in this environment share the reference to the number variable in this environment, so they can all operate on number. .

Example 3: Each calling function will create a different closure environment.

Let’s give a very simple example.

function newClosure() {
  let array = [1, 2];
  return function(num) {
    array.push(num);
    console.log(`array:${array}`);
  }
}
let myClosure = newClosure();
let yourClosure = newClosure();
myClosure(3); // array:1,2,3
yourClosure(4); // array:1,2,4
myClosure(5); // array:1,2,3,5
Copy after login

In the above example, the assignment statement of myClosure and yourClosure, that is, the newClosure function is called twice, thus creating two different closure environments, so the variables inside do not affect each other. .

Example 4: Creating a closure inside a loop

function newClosure() {
  for(var i = 0; i < 5; i++) {
    setTimeout(function() {
      console.log(i);
      })
  }
}
newClosure(); // 5个5
Copy after login

打印的结果大家也知道是5个5,因为 setTimeout 里面的函数保持对 i 的引用,在setTimeout的回调函数被执行的时候这个循环早已经执行完成,这里我之前在另一篇文章里面做过更深入的介绍:深入浅出Javascript事件循环机制(上)。

这里我要说的是我们如何才能得到我们想要的01234,在这里有两种做法。

一种是 创建一个新的闭包对象,这样每个闭包对象里面的变量就互不影响。例如下面的代码种每次 log(i)都会创建不同的闭包对象,所有的回调函数不会指向同一个环境。

function log(i) {
  return function() {
    console.log(i);
  }
}
function newClosure() {
  for(var i = 0; i < 5; i++) {
    setTimeout(log(i));
  }
}
newClosure(); // 0 1 2 3 4
Copy after login

另一种做法就是使用自执行函数,外部的匿名函数会立即执行,并把 i 作为它的参数,此时函数内 e 变量就拥有了 i 的一个拷贝。当传递给 setTimeout 的匿名函数执行时,它就拥有了对 e 的引用,而这个值是不会被循环改变的。写法如下:

function newClosure() {
  for(var i = 0; i < 5; i++) {
    (function(e) {
      setTimeout(function() {
        console.log(e);
      })
    })(i)  
  }
}
newClosure(); // 0 1 2 3 4
Copy after login

看看,写这么多,多累是不是,还是let省事,所以赶紧拥抱 es6 吧。。。

好了,这次是真的结束了,我所理解的闭包大概就是这样了,如果理解有所偏差,欢迎指出,谁当初不是从颗白菜做起的呢,学习前端的小伙伴们可以看看哦!

关于闭包:

js中作用域与函数闭包实例讲解

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

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

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

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Recommended: Excellent JS open source face detection and recognition project Recommended: Excellent JS open source face detection and recognition project Apr 03, 2024 am 11:55 AM

Face detection and recognition technology is already a relatively mature and widely used technology. Currently, the most widely used Internet application language is JS. Implementing face detection and recognition on the Web front-end has advantages and disadvantages compared to back-end face recognition. Advantages include reducing network interaction and real-time recognition, which greatly shortens user waiting time and improves user experience; disadvantages include: being limited by model size, the accuracy is also limited. How to use js to implement face detection on the web? In order to implement face recognition on the Web, you need to be familiar with related programming languages ​​and technologies, such as JavaScript, HTML, CSS, WebRTC, etc. At the same time, you also need to master relevant computer vision and artificial intelligence technologies. It is worth noting that due to the design of the Web side

What is the meaning of closure in C++ lambda expression? What is the meaning of closure in C++ lambda expression? Apr 17, 2024 pm 06:15 PM

In C++, a closure is a lambda expression that can access external variables. To create a closure, capture the outer variable in the lambda expression. Closures provide advantages such as reusability, information hiding, and delayed evaluation. They are useful in real-world situations such as event handlers, where the closure can still access the outer variables even if they are destroyed.

What are the advantages and disadvantages of closures in C++ functions? What are the advantages and disadvantages of closures in C++ functions? Apr 25, 2024 pm 01:33 PM

A closure is a nested function that can access variables in the scope of the outer function. Its advantages include data encapsulation, state retention, and flexibility. Disadvantages include memory consumption, performance impact, and debugging complexity. Additionally, closures can create anonymous functions and pass them to other functions as callbacks or arguments.

How to implement closure in C++ Lambda expression? How to implement closure in C++ Lambda expression? Jun 01, 2024 pm 05:50 PM

C++ Lambda expressions support closures, which save function scope variables and make them accessible to functions. The syntax is [capture-list](parameters)->return-type{function-body}. capture-list defines the variables to capture. You can use [=] to capture all local variables by value, [&] to capture all local variables by reference, or [variable1, variable2,...] to capture specific variables. Lambda expressions can only access captured variables but cannot modify the original value.

The relationship between js and vue The relationship between js and vue Mar 11, 2024 pm 05:21 PM

The relationship between js and vue: 1. JS as the cornerstone of Web development; 2. The rise of Vue.js as a front-end framework; 3. The complementary relationship between JS and Vue; 4. The practical application of JS and Vue.

The role of golang function closure in testing The role of golang function closure in testing Apr 24, 2024 am 08:54 AM

Go language function closures play a vital role in unit testing: Capturing values: Closures can access variables in the outer scope, allowing test parameters to be captured and reused in nested functions. Simplify test code: By capturing values, closures simplify test code by eliminating the need to repeatedly set parameters for each loop. Improve readability: Use closures to organize test logic, making test code clearer and easier to read.

Chained calls and closures of PHP functions Chained calls and closures of PHP functions Apr 13, 2024 am 11:18 AM

Yes, code simplicity and readability can be optimized through chained calls and closures: chained calls link function calls into a fluent interface. Closures create reusable blocks of code and access variables outside functions.

The impact of function pointers and closures on Golang performance The impact of function pointers and closures on Golang performance Apr 15, 2024 am 10:36 AM

The impact of function pointers and closures on Go performance is as follows: Function pointers: Slightly slower than direct calls, but improves readability and reusability. Closures: Typically slower, but encapsulate data and behavior. Practical case: Function pointers can optimize sorting algorithms, and closures can create event handlers, but they will bring performance losses.

See all articles