This is the 10th day of my participation in the More text Challenge. For more details, see more text Challenge
preface
In our last article, “Scopes and Scope Chains in JavaScript,” we took a closer look at scopes and scope chains in JavaScript. With scope as a base, it’s easy to look at closures, so let’s talk about closures in JavaScript today. If you learn to like it after watching it, you’d better pay attention (hey hey hey…) “And then comment” learned “, if learned, please comment “learned”, do not appear “learned, but not completely learned”, “learned, but not completely learned” situation ~
Ok, let’s start our happy study together!
What is a closure
A closure is a combination of a function and the lexical context in which it is declared. This sentence may be confusing for beginners, but let me explain this sentence:
Function: Internal function declares this function: External function Lexical environment: scope (scope chain, see previous article for details) Combination: synthesis of the above
Once we understand what the above statement means, we can see the conditions under which closures are formed:
The two functions are nested. The inner function accesses a variable declared by the outer function.
From this, we can see that the basic model of closures is as follows:
function outer(){
var num = 100
function inner(){
console.log(num)
}
return inner
}
var ret = outer()
ret()
Copy the code
What closures do
First, private variables, to protect the security of data
Most of the time, we don’t want the data to be changed externally, we want the changes to be limited to the extent that the changes to the data are safe to maintain.
Let’s take a look at a counter function made with a closure. In this counter function, we want to protect the count variable, except for the internal return fn function, which can change the value of count. The following code:
// Function: count the number of fn calls
function outer(){
var count = 0
function fn(){
count++
console.log("Function fn is called." + count + "Time")}return fn
}
var ret = outer()
ret()
Copy the code
Second, persist data
In the counter function above, one question arises: Why is ret called with the count value at ++ instead of starting at 0 each time?
This is because when a function is called, it creates a space in memory to execute the code inside the function, and when the call ends, the space is destroyed. In the counter function above, the value of count is stored in the outer function. The outer function as a whole is not destroyed, and so is the value of count.
What can we do with closures? Like when you calculate the Fibonacci sequence.
Fibonacci sequence, also known as golden section sequence, was introduced by mathematician Leonardoda Fibonacci by taking rabbit reproduction as an example, so it is also called “rabbit sequence”, which refers to a sequence like this: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34… Mathematically, the Fibonacci sequence is defined recursively as follows: F(0)=0, F(1)=1, F(n)=F(n-1)+F(n-2) (n ≥ 2, n ∈ n *)
Now, we’re going to generate a Fibonacci sequence, and there’s a lot of repeated calculations, so if we want to get Fibonacci’s thousandth number, how long does it take? The following code:
const fb = function() {
function fn(n) {
if (n === 1 || n === 2) {
return 1
}
var num = fn(n - 1) + fn(n - 2)
return num
}
return fn
}()
console.log(fb(100))
Copy the code
You may find that your browser is stuck because too much memory is being used for repeated calculations. But what about using closures to persist data (caching)? The following code:
const fb = function() {
var cache = [0.1] // Create the cache
function fn(n) {
var num = cache[n]
if(typeofnum ! = ='number') {// If the cache has no Fibonacci value for the current bit
cache[n] = fn(n-1) + fn(n-2) // Add the Fibonacci value corresponding to the current bit to cache
num = cache[n]
}
return num // If the cache has Fibonacci values for the current bit, return the Fibonacci value
}
return fn
}()
console.log(fb(1000))
Copy the code
As we can see, even if the calculated value is a 1000 digit number, the result will come out in seconds. The more complex the Fibonacci sequence calculation, the faster the persistence of the data using closures.
Closure memory leak
What is a memory leak? Colloquial, a memory leak is when a declared variable, which is not used, is not destroyed at the end of js execution. In other words, a memory space is occupied, and it is not reclaimed. Other objects can no longer use the memory space.
A lot of tutorial material says that using closures is a sure way to leak memory, but that’s a loose statement.
We need to be clear: JavaScript memory free mechanism does not need human manipulation, is the JS engine automatically free.
Speaking of memory leaks, it was before IE9 that closure variables caused memory leaks. This is because the garbage collection algorithm used before IE9 was not the mark-clean algorithm used today, but the reference counting algorithm. Reference counting algorithms deal with COM objects (component object model) with circular references, which are the main cause of memory leaks. In early V8, because the variable referenced by the closure was mounted in the global large object Windows, this variable was collected by the old generation area using the mark-clean algorithm. Frequent garbage collection generates a lot of memory fragmentation, which can also lead to memory leaks. In order to solve this problem, and the full pause problem caused by frequent garbage collection (garbage collection is performed on the main thread), V8 later adopted the mark-clean collation algorithm, as well as garbage collection technologies such as incremental collection, parallel collection, and concurrent collection.
One, reference counting algorithm
Js will automatically allocate memory, store objects, and periodically check the number of times the object is referenced to determine whether to recycle. The following code:
// Assign the address of the created object to the variable obj. This object is referenced, and the object reference count is 1 (this object is not garbage collected).
var obj = {
name: "Big ice."
}
// assign the address of obj to the variable one. One also points to the object, which is referenced twice (not reclaimed).
var one = obj
// If obj = 1, obj does not point to an object, but if obj is referenced once, it will not be reclaimed.
obj = 1
// In this case, change one = null, so that one does not point to the object, and the object is referenced 0 times. If the object is referenced 0 times, it is marked as garbage memory and is reclaimed by the garbage collection mechanism.
one = null
Copy the code
A flaw in reference counting: errors in circular references. The following code:
function fn(){
var obj1 = {} // {} This object is referenced once
var obj2 = {} // {} This object is referenced twice
obj1.a = obj2 // {} This object is referenced three times
obj2.b = obj1 // {} This object is referenced four times
}
// Fn is called, obj1 and obj2 should be destroyed, but because neither object is a zero-reference object, they cannot be reclaimed.
fn()
fn()
fn()
fn()
fn()
If fn is called multiple times, it will cause a memory leak.
Copy the code
Two, mark-clear algorithm
Start with the window and work your way down from the root object. If no variable referencing the object is found, the object is reclaimed as garbage memory. So the mark-clear algorithm solves the problem of circular references.
var obj = {
name: "Big ice."
}
obj = null // There is no reference to '{name: "big ice "}', and the object is reclaimed.
Copy the code
Since 2012, all modern browsers have used the mark-clean garbage collection algorithm, so there are almost no memory leaks with closures in the next generation of browsers.
Of course, there is a final solution to the problem of pages using too much memory, if the closure is leaking, and that is to manually release the memory used by the closure:
function outer(){... }var ret = outer()
ret = null
Copy the code
Afterword.
After learning this article, you will have a deeper understanding of closures and will never be afraid to encounter them in an interview. Finally, let me give you an example. It’s like when you finish reading this article, you like it, you like it, you like it, you like it, you like it, you like it, you like it, you like it, you like it, you like it, you like it, you like it, you like it, you follow it. Got it?
PS: today is my 10th day to participate in the nuggets more text challenge, I did not save draft, every day to look at the article, has insisted on 10 days! Where there is a will, there is a way. Come on, everybody
The list of more challenging articles is as follows:
- Flex layout container elements and project elements attributes
- 2021.06.02 how to play with CSS Gradient Background
- How to Use SVG to create Text Effects along Arbitrary Paths
- 2021.06.04 “Front-end code specification of 3 categories and 15 subcategories, let the team code be standardized!”
- Git Commit Specification for team management: How many people don’t write commit records?
- 2021.06.06 “How to Control CSS mouse Style and Expand mouse Click area | Weekend study”
- 2021.06.07 “Pure CSS implementation: imitation gold mining account password login, the red panda wu eye action switch small Egg”
- On Prototypes and Prototype Chains in 11 Aspects
- A Closer Look at JavaScript scope and Scope Chains