Understanding closure

Posted by newb on Sun, 13 Feb 2022 11:52:51 +0100

closure

Rhinoceros book: if a function variable can be saved in the scope of a function, it can be called a closure

Advanced Programming: closure refers to a function that has access to variables in the scope of another function (the function is not exported);

javascript you don't know: when a function can remember and access its lexical scope, a closure is generated, even if the function is executed outside the current lexical scope

function foo(){
    let n = 0;
}
//Example 1
function(){
    let n = 0;
    function bar(){
        console.log(n)
    }
}

//Example 2
// closure
function fn(callback){
  let num = 18
  return callback(num)
}

fn(function(){
  console.log([].shift.call(arguments));
})

The function of closures is to prolong the life cycle of variables

Conditions for forming closures?

  1. Function nesting
  2. Function export
  3. The scope of the parent function can be accessed
  4. When a function is executed, it causes the function to be defined or thrown

Closure thinking problem

  1. Can you get n in test?
  2. Why can't I get it n?
  3. What should I do if I want to get it
function fn(callback){
  let n = 99
  callback()
}

function test(){
  console.log(n);
}

fn(test)


//It may be seen in many cases, which is slightly different from the above 
function fn(callback){
  let n = 99
  return callback(n)
}

let res = fn(n => n)
console.log(res);

Personal understanding and answer:

1. No
2. because test Function found scope in current function body n This variable will then go up to the next level and can't be found,
3. If you want to get it, you can callback()Inside, then test receive   `perhaps`  Return a function definition and then call it outside, so it can be printed to n The value of is actually because the function is still calling, and the scope of the upper level function has not been destroyed, which verifies that the function of closures is to prolong the life cycle of variables

Form of closure

1.The return value of the function is the function
function foo(fn){
    let n = 0;
    return function(){}
}

2.The returned variable is a function
function foo(){
    let n = function(){}
    return n
}
foo()

3.Closure defined by global variable
let outter;
function foo(){
    let a = 10;
    outter = function(){
        console.log(a)
    }
}
foo();
outter()

4.The way of function parameters is very common
let inner = function(fn){
    console.log(fn())
}

;(function(){
    let b = "local";
    let n = function(){
        return b
    }
    inner(n)
})()

5.Cyclic assignment
function foo(){
  let arr = []
  for (let i = 0; i < 10; i++) {
    arr[i] = function(){
      console.log(i);
    }
  }
  return arr
}

let res = foo();
res.forEach(fn => {
  fn()
})

I understand why closures can extend the scope of variables?

  • Because each function call creates a new scope, and the parent environment will be preserved when the child function is used
  • Using let/const, you can declare variables in the block scope (in the new environment, not in the global)

Make a question and understand the closure

function fun(n,o){
  console.log(o);
  return {
    fun(m){
      return fun(m,n)
    }
  }
}

//1. Ask what to print
let a = fun(0)  
a.fun(1)
a.fun(2)
a.fun(3)

//undefined 0 0 0
  • Needless to say, why is the first undefined 0?
    • Because when the child function is used, the parent environment (i.e. scope) will be retained, and then n in the parent function will be found. At that time, n passed in 0, so it is printed 0

Let's analyze the scope

//Pseudo code

//Execute let a = fun(0)
|-- fun(n,o)Scope
	n = 0 ,o = undefined   //There is an internal function to execute. This scope is reserved

	//Execute a.fun(1)
	a : {
        fun(1) return fun(m,n)  //(1,0)
        //At this time, the scope of the parent function will be reserved, m = 1, and then look up n and find n = 0 (here n is the first formal parameter of the fun function. Don't be confused)
    }
    
	//Execute a.fun(2)   
	a : {
        fun(2) return fun(m,n)  //(2,0) n will look up
    }
	
	//Execute a.fun(3)   
	a : {
        fun(2) return fun(m,n) //(3,0) n will look up
    }

How about this?

function fun(n,o){
  console.log(o);
  return {
    fun(m){
      return fun(m,n)
    }
  }
}

//2. Ask what to print
let b = fun(0).fun(1).fun(2).fun(3);  
//undefined 0 1 2

We also use pseudo code to analyze the scope

//Pseudo code
//Execute fun(0)
function(n,o){    
    //N = 0, o = undefined the scope variable has not been destroyed
    console.log(o) //Print undefined
    
    //Execute fun (0) fun(1)
    function(n,o){
        //n = 1,o=0
           console.log(o) //Print 0
        
        //Execute fun (0) fun(1). fun(2)
        function(n,o){
            //n = 2 ,o = 1
            console.log(o) //Print 1
            
            //Execute fun (0) fun(1). fun(2). fun(3)
            function(n,o){
                //n = 3 ,o = 2
                console.log(o) //Print 2
            }(3,2)
            
        }(2,1) //At this time, n = 1 is found in the previous scope 
        
    }(1,0) //At this time, n = 0 is found in the previous scope
    
}(0)

  • Nested layer by layer, the previous scope has not been destroyed

Can we understand this as the function of closures? Is to extend the life cycle of variables,

Why is it extended? Because the scope of the parent function will not be destroyed when the child function is in use

Change it again

function fun(n,o){
  console.log(o);
  return {
    fun(m){
      return fun(m,n)
    }
  }
}

let c = fun(0).fun(1);
c.fun(2);
c.fun(3);

  • You should be able to answer this question directly
  • undefine 0 1 1

summary

The function of closures is to prolong the life cycle of variables

Why? Because the scope of the parent function will not be destroyed when the child function is in use

Conditions for forming closures?

  1. Function nesting
  2. Function export
  3. The scope of the parent function can be accessed
  4. When a function is executed, it causes the function to be defined or thrown

Topics: Javascript Front-end