Home Web Front-end JS Tutorial An experienced driver will help you thoroughly understand the various pitfalls of JS closures

An experienced driver will help you thoroughly understand the various pitfalls of JS closures

Nov 25, 2019 pm 05:00 PM
js pit Closure

An experienced driver will help you thoroughly understand the various pitfalls of JS closures

The old driver will help you thoroughly understand the various pitfalls of JS closures

Closures are js Common development techniques, what are closures?

A closure refers to a function that can access variables in the scope of another function. To put it clearly: a closure is a function that can access variables in the scope of other functions. eg:

function outer() {
     var  a = '变量1'
     var  inner = function () {
            console.info(a)
     }
    return inner    // inner 就是一个闭包函数,因为他能够访问到outer函数的作用域
}
Copy after login

Many people will not understand the relationship between anonymous functions and closures. In fact, closures are defined from the perspective of scope, because inner accesses variables in outer scope, so inner is a closure function. Although the definition is very simple, there are many pitfalls, such as this pointer and the scope of variables. A little carelessness may cause memory leaks. Let’s put the problem aside and think about a question: Why can closure functions access the scope of other functions?

Looking at js functions from the perspective of the stack

Basic variables The value of is generally stored in the stack memory, while the value of the object type variable is stored in the heap memory, and the stack memory stores the corresponding space address. Basic data types: Number, Boolean, Undefined, String, Null.

var  a = 1   //a是一个基本类型
var  b = {m: 20 }   //b是一个对象
Copy after login

Corresponding memory storage:

An experienced driver will help you thoroughly understand the various pitfalls of JS closures

When we execute b={m:30}, there is a new object {m:30} in the heap memory , b in the stack memory points to the new space address (pointing to {m: 30}), and the original {m: 20} in the heap memory will be garbage collected by the program engine, saving memory space. We know that js functions are also objects, and they are also stored in heap and stack memory. Let’s take a look at the transformation:

var a = 1;
function fn(){
    var b = 2;
    function fn1(){
        console.log(b);
    }
    fn1();
}
fn();
Copy after login

An experienced driver will help you thoroughly understand the various pitfalls of JS closures

**

The stack is A first-in, last-out data structure:

1 Before executing fn, we are in the global execution environment (the browser is the window scope), and there is a variable a in the global scope;

2 Enter fn. At this time, the stack memory will push an execution environment of fn. This environment contains variable b and function object fn1. Here you can access the variables defined by its own execution environment and the global execution environment

3 Enter fn1. At this time, the stack memory will push an execution environment of fn1. There are no other variables defined in it, but we can access the variables in fn and the global execution environment, because when the program accesses the variables, it moves to the bottom stack. If you find that there is no corresponding variable in the global execution environment, the program will throw an underfined error.

4 As fn1() is executed, the execution environment of fn1 is destroyed by cup, and then fn() is executed, the execution environment of fn will also be destroyed, leaving only the global execution environment, and now there is no b Variables, and fn1 function objects, only a and fn (the function declaration scope is under window)

**

Accessing a variable within a function is judged according to the function scope chain Whether the variable exists, and the function scope chain is initialized by the program according to the execution environment stack where the function is located, so in the above example, we print variable b in fn1, and find the corresponding fn execution environment according to the scope chain of fn1 variable b. So when the program calls a function, it does the following work: prepare the execution environment, initial function scope chain and arguments parameter object

We now look back at the original example outer and inner

function outer() {
     var  a = '变量1'
     var  inner = function () {
            console.info(a)
     }
    return inner    // inner 就是一个闭包函数,因为他能够访问到outer函数的作用域
}
var  inner = outer()   // 获得inner闭包函数
inner()   //"变量1"
Copy after login

When the program finishes executing var inner = outer(), in fact, the execution environment of outer is not destroyed, because the variable a inside it is still referenced by the function scope chain of inner. When the program finishes executing inner(), this Only when the execution environment of inner and outer will be destroyed and adjusted; the book "JavaScript Advanced Programming" recommends: Because closures will carry the scope of the function containing them, because they will occupy more content than other functions, excessive use of closures , will cause excessive memory usage.

Now we understand the closure, the corresponding scope and scope chain, return to the topic:

Pitfall 1: The referenced variables may change

function outer() {
      var result = [];
      for (var i = 0; i<10; i++){
        result.[i] = function () {
            console.info(i)
        }
     }
     return result
}
Copy after login

It seems that each closure function in the result prints a corresponding number, 1, 2, 3, 4,...,10. This is not actually the case because each closure function accesses the variable i in the outer execution environment. Variable i, as the loop ends, i has become 10, so each closure function is executed, and the result prints 10, 10, ..., 10

How to solve this problem?

function outer() {
      var result = [];
      for (var i = 0; i<10; i++){
        result.[i] = function (num) {
             return function() {
                   console.info(num);    // 此时访问的num,是上层函数执行环境的num,数组有10个函数对象,每个对象的执行环境下的number都不一样
             }
        }(i)
     }
     return result
}
Copy after login

Pit point 2: this points to the problem

var object = {
     name: &#39;&#39;object",
     getName: function() {
        return function() {
             console.info(this.name)
        }
    }
}
object.getName()()    // underfined
// 因为里面的闭包函数是在window作用域下执行的,也就是说,this指向window
Copy after login

Pit point 3: Memory leak problem

function  showId() {
    var el = document.getElementById("app")
    el.onclick = function(){
      aler(el.id)   // 这样会导致闭包引用外层的el,当执行完showId后,el无法释放
    }
}
// 改成下面
function  showId() {
    var el = document.getElementById("app")
    var id  = el.id
    el.onclick = function(){
      aler(id)   // 这样会导致闭包引用外层的el,当执行完showId后,el无法释放
    }
    el = null    // 主动释放el
}
Copy after login

Tip 1: Use closures to solve recursive calling problems

function  factorial(num) {
   if(num<= 1) {
       return 1;
   } else {
      return num * factorial(num-1)
   }
}
var anotherFactorial = factorial
factorial = null
anotherFactorial(4)   // 报错 ,因为最好是return num* arguments.callee(num-1),arguments.callee指向当前执行函数,但是在严格模式下不能使用该属性也会报错,所以借助闭包来实现
// 使用闭包实现递归
function newFactorial = (function f(num){
    if(num<1) {return 1}
    else {
       return num* f(num-1)
    }
}) //这样就没有问题了,实际上起作用的是闭包函数f,而不是外面的函数newFactorial
Copy after login

** Tip 2: Use closures to imitate block-level scope**

es6 is not out Previously, there was a variable promotion problem when using var to define variables, eg:

for(var i=0; i<10; i++){
    console.info(i)
}
alert(i)  // 变量提升,弹出10

//为了避免i的提升可以这样做
(function () {
    for(var i=0; i<10; i++){
         console.info(i)
    }
})()
alert(i)   // underfined   因为i随着闭包函数的退出,执行环境销毁,变量回收
Copy after login

Of course, most of them are now defined using es6's let and const.

This article has ended here. For more exciting content, you can pay attention to the JavaScript Video Tutorial column on the PHP Chinese website!

The above is the detailed content of An experienced driver will help you thoroughly understand the various pitfalls of JS closures. 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

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 ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
1 months ago By 尊渡假赌尊渡假赌尊渡假赌
Will R.E.P.O. Have Crossplay?
1 months ago By 尊渡假赌尊渡假赌尊渡假赌

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.

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.

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.

Solve the memory leak problem caused by closures Solve the memory leak problem caused by closures Feb 18, 2024 pm 03:20 PM

Title: Memory leaks caused by closures and solutions Introduction: Closures are a very common concept in JavaScript, which allow internal functions to access variables of external functions. However, closures can cause memory leaks if used incorrectly. This article will explore the memory leak problem caused by closures and provide solutions and specific code examples. 1. Memory leaks caused by closures The characteristic of closures is that internal functions can access variables of external functions, which means that variables referenced in closures will not be garbage collected. If used improperly,

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 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.

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.

See all articles