5
头图

Wide sea diving, sky high the birds to fly. Hey hello! I'm Molly

Closures are already a commonplace issue, and different people have different understandings of closures. Today I'm going to talk about closures. Let's discuss the topic of "closures" together, hoping to create some different sparks.

Before understanding closures, we must first understand the two knowledge points of " context " and " scope "

context

When the browser engine parses the js code, it roughly goes through two stages. parsing phase and execution phase

Parsing stage : A piece of code is just a regular piece of code text, so the js engine will parse the code in advance when it gets the code. During the initialization process, it will extract variables, parameters, functions, expressions, operators, etc. coexist, and assign the variable to undefined by default, the function to be a function block by default, to determine the context relationship and a series of preparations

Execution stage : Execute the code line by line from top to bottom, if the corresponding variable or function is encountered, go to the warehouse to match and execute

console.log(str);
console.log(fun);
var str = "molly";
let str1;
console.log(str1);
function fun(a, b) {
    return a + b;
}

definition: context can be divided into global context and local context , the context determines which data variables or functions they can access, and their behavior (it has been determined in the initialization phase), each context has a variable object (environment record) , all variables and functions defined in this context will be stored in this variable object , we cannot directly access this variable object through code, but we can view it by breaking points .

The global context will be destroyed before the program exits (such as closing the web page or exiting the browser), and the local context will be destroyed after its code has finished executing

So what does this variable object look like? Don't worry, let's look down

context execution stack

Definition: Each function call has its own context. When the function is executed, the context of the function will be pushed into a context execution stack. Control is returned to the previous execution context.

// 一个简单的例子,断点调试调用栈和上下文变量对象
let a_name = "猫力";
var a_sex = "男";
var a = "111";
function a_molly(age) {
    let a_like = "爱学习";
    var a_like2 = "爱运动";
    a_say(a_like);
    var a = "222";
    console.log(a);
    let test = "来啦?";
}
function a_say(a_like) {
    let code = "敲代码";
    console.log(a_like);
}
a_molly();

Execute the above example code, we set a breakpoint on the console to observe the process of execution stack (call stack)

 执行栈.jpg

Pay attention to the call stack (execution stack) on the left and the scope (environment record) on the right as well as the breakpoint location

By observing the breakpoint debugging results, we can draw the following conclusions:

  • When the script program is initialized, a global context is pushed to the bottom of all context execution stacks, that is, the Global property
  • Whenever a function is executed, a "function context" will be added to the execution stack
  • When the function is executed, it will clear the corresponding "function context"
  • Inside each context, the data that can be accessed is determined

Scope and scope chain

When the code in the context executes, it creates a scope chain of variable objects. This scope chain determines the order in which variables and functions are accessed by code in each level of context. The scope is a containment relationship, and the global contains the local.

:

The context is associated with the variable object and determines what data the function can access, while the scope determines the rules for data access.

In simple terms, the access rules of the scope can be summarized as: search and access from the inside out, the inside can access the outside but the outside cannot access the inside, such an access method can be called a scope chain

Function parameters are considered variables in the current context and therefore follow the same access rules as other variables in the context.

Closure

Now that we have briefly understood the two knowledge points of " context " and " scope ", it is very friendly to talk about closure

Definition of Closure

Red Book: Closures are those functions that reference variables in the scope of another function

MDN: function is bundled with a reference to its surrounding state ( lexica environment , the lexical environment) (or the function is surrounded by references), such a combination is a closure ( closure ). That is, closures allow you to access the scope of an outer function from within an inner function. In JavaScript , whenever a function is created, the closure is created at the same time as the function is created.

Ruan Yifeng: closure is a function that can read the internal variables of other functions. Only subfunctions inside a function can read local variables, so closures can be simply understood as "functions defined inside a function".

To sum up: The execution of a function can trigger the definition of another function (function declaration, function expression), and supports referencing variables in the scope of another function. Then this function is a closure

Why are there closures?

In summary, we can know that the local scope can access the global scope, but the global cannot access the local, and two unrelated locals cannot access each other. So, as long as the thinking does not slip, the solution is always more difficult than the difficulty. We need to work around this kind of problem, and the conclusion is: "closure" .

Closures are like a bridge, connecting multiple unrelated scopes to achieve interoperability.

The principle of closure is to use the variable environment and scope chain access rules

Use of closures

There are two biggest uses of closures

  1. Can read the internal variables of the function body
  2. Keep the variables of the closure always in memory

The form of the closure:

Treat the function as a first-class citizen, as an ordinary variable

1: return a function

function fun(){
    var aaa = 111
    return function(b){
        return aaa+b
    }
}
fun()()
经典场景:防抖节流

2: return a function variable

function fun(a){
    let fn =  function(b){
        return a+b
    }
    return fn;
}
fun()()

3: As a global closure function

var call;
function fun(a){
    call =  function(b){
        return a+b
    }
}
fun()
call()

4: Pass as function parameter

function fun1(fn){
    fn() //这个fn函数就是闭包
}
function fun2(){
    let str = 'molly'
    function fun3(){
        console.log(str)
    }
    fun1(fun3)
}
fun2()

5: Callback function


function ajax(data){
    console.log(data)
}
function sync(){
    const obj = {name:'molly',a:a}
    ajax(obj)
}

6: IIFE executes the function immediately

;!(function(){
   ...
});

经典场景:
for(var i = 1;i <= 5;i++){
  (function(j){
    setTimeout(function timer(){
      console.log(j)
    }, 0)
  })(i)
}
jquery自定义封装插件也是从立即执行函数开始的

Advantages of closures:

  1. Can access two unrelated scoped variables
  2. as a sandbox, storing variables
  3. Code encapsulation, utility functions
  4. Functions as values, take arguments and return

Disadvantages of closures:

  1. memory leak

How to avoid memory leaks?

  1. Point the function pointer to null and bring it into the scope of garbage collection
  2. Execute the closure
function fun(a){
    return function(b){
        return a+b
    }
}
let a = fun()
a=null

再或者将闭包也执行完毕

a()

Here is a brief mention of why closures cause memory leaks. The garbage collection mechanism of js is roughly divided into two types: "mark cleaning" and "counting references" . When a variable in a closure is used in another function, the variable will not be recognized as garbage, but will not be cleaned up in resident memory. cause extra memory consumption

Questions?

Do you know of any scenarios or code that use closures cleverly? Welcome to leave a message in the comment area to discuss!

grateful

Welcome to pay attention to my personal public number There are tricks in the front end to push you fresh and high-quality good articles every day. Reply to "welfare" to get the front-end knowledge spree I carefully prepared. May you go all the way with light in your eyes!

Interested friends can also add me WeChat: Maoli molly or Front-end exchange group and many excellent front-end siege lions to exchange technology and play together!


前端有猫腻
556 声望638 粉丝