


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函数的作用域 }
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是一个对象
Corresponding memory storage:
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();
**
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"
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 }
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 }
Pit point 2: this points to the problem
var object = { name: ''object", getName: function() { return function() { console.info(this.name) } } } object.getName()() // underfined // 因为里面的闭包函数是在window作用域下执行的,也就是说,this指向window
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 }
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
** 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随着闭包函数的退出,执行环境销毁,变量回收
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!

JavaScript is widely used in websites, mobile applications, desktop applications and server-side programming. 1) In website development, JavaScript operates DOM together with HTML and CSS to achieve dynamic effects and supports frameworks such as jQuery and React. 2) Through ReactNative and Ionic, JavaScript is used to develop cross-platform mobile applications. 3) The Electron framework enables JavaScript to build desktop applications. 4) Node.js allows JavaScript to run on the server side and supports high concurrent requests.

Python is more suitable for data science and automation, while JavaScript is more suitable for front-end and full-stack development. 1. Python performs well in data science and machine learning, using libraries such as NumPy and Pandas for data processing and modeling. 2. Python is concise and efficient in automation and scripting. 3. JavaScript is indispensable in front-end development and is used to build dynamic web pages and single-page applications. 4. JavaScript plays a role in back-end development through Node.js and supports full-stack development.

C and C play a vital role in the JavaScript engine, mainly used to implement interpreters and JIT compilers. 1) C is used to parse JavaScript source code and generate an abstract syntax tree. 2) C is responsible for generating and executing bytecode. 3) C implements the JIT compiler, optimizes and compiles hot-spot code at runtime, and significantly improves the execution efficiency of JavaScript.

JavaScript's application in the real world includes front-end and back-end development. 1) Display front-end applications by building a TODO list application, involving DOM operations and event processing. 2) Build RESTfulAPI through Node.js and Express to demonstrate back-end applications.

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


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

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

Hot Article

Hot Tools

VSCode Windows 64-bit Download
A free and powerful IDE editor launched by Microsoft

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

PhpStorm Mac version
The latest (2018.2.1) professional PHP integrated development tool

SublimeText3 English version
Recommended: Win version, supports code prompts!

Atom editor mac version download
The most popular open source editor