JavaScript advanced part-03 (this point / context execution mode / recursion / closure)

1.this point

  • Function has three execution modes: global function, object method and constructor
  • this: I point to whoever calls me (independent of the function declaration, depending on the function call)
  1. Global function: function name () -------------- > this points to window
  2. Object method: object name Method name () ---- -- > this points to the object
  3. Constructor: new function name () ------------- > this points to the empty object created by new

Analysis of this pointing experience: this pointing depends on the function call, and the function has three calling methods. So there are three situations when this points
(1) The exclusion method is preferred. If there is a new keyword, it points to the object created by new. Otherwise, it is either a window or an object
(2) How to judge whether this is a window or an object depends on whether the call is a function name () or an object name Method name ()

        let obj = {
            name: 'ikun',
            sayHi: function () {
                function fn() {
                    console.log(this);
                }
                fn()// Ordinary function call: the function name () fn calls this, so this points to window 
            }
        }
        obj.sayHi()//window
        let obj1 = {
            name: 'ikun',
            sayHi: function () {
                console.log(this);
            }
        }
        obj1.sayHi() //Object method call: object name Method name () object obj1 called this, so this points to obj1 object
        function Fn() {
            console.log(this);
        }
        new Fn()//Constructor call: new function name () executes the process according to new / creates an empty object - this points to this object - object assignment - returns the object, where this points to the empty object created by new

Common feature: the direction of this cannot be dynamically modified

2. Function context execution mode (call/apply/bind)

2.1 context mode considerations

  • a. The Function context has three methods: call() apply() bind(), which are defined in the prototype of the Function constructor
  • b. If you change this point to the value type: (number,boolean,string), the function will automatically wrap it into the corresponding reference type (basic wrapper type)
    • Value type: '123',1,true
    • Basic packing type: String('123'),Number(1),Boolean(true)

2.2 function context function:

this point in the function can be dynamically modified

2.3 similarities and differences:

  • The same thing: you can modify the point of this in the function
  • difference:
    1. Different parameter transfer methods: call refers to one-to-one parameter transfer, and apply refers to array / pseudo array parameter transfer
    2. Different execution mechanisms: call and apply will execute the function immediately, while bind will not execute the function immediately

2.3 syntax

There are three ways to write. The functions are the same. Change this and the application scenarios are different

  • call() syntax: function name call(this modified point, parameter 1, parameter 2,...)-------------- Applicable to function parameter < = 1
  • apply() syntax: function name apply(this modified point, pseudo array or array) ----------------- applicable to the original parameter of the function > = 2
  • bind() syntax: function name bind(this modified point)
    The bind() syntax does not execute the function immediately, but returns a new function after modification, which is often used in callback functions
    If the parameter is passed during bind, the parameter will also be bound, and the argument cannot be passed later
  	<script>
        /* 
        1.Functions can be executed in three ways: 
            Global function: this points to window
            Object method: this points to the object
            Constructor: this points to the object created by new
                Common feature: the direction of this cannot be dynamically modified

        2.Function context mode: 
            2.1 Function: you can dynamically modify this in the function
            2.2 Syntax: there are three ways of writing. The functions are the same. Change this and the application scenarios are different
                a. Function name Call (modified this,arg1,arg2.............) 
                    * Applicable to function parameter < = 1
                b. Function name Apply (modified this, [array or pseudo array])
                    * Applicable to function parameter > = 2
                c. Function name Bind (modified this,arg1,arg2.............)
                    * Features: this function will not be executed immediately, but will return the new function after modifying this
                    * Applicable to functions that will not be executed immediately: event handling function, timer function
        */

        // function fn(){
        //     //The three execution modes this cannot be dynamically modified
        //     //this = {age:18};

        //     console.log(this);

        // };

        // fn();//this:window

        /* Context mode */
        function fn(a, b) {
            console.log(this);
            console.log(a + b);
        };

        //a. Function name Call (modified this,arg1,arg2.............) 
        //Application scenario: applicable to function original parameter < = 1
        fn(10, 20);//this:window   30
        fn.call({ age: 18 }, 100, 200); //age:18  300

        //b. Function name Apply (modified this, [array or pseudo array])
        //Application scenario: applicable to function parameter > = 2
        fn.apply({ age: 88 }, [20, 30]);

        //c. Function name Bind (modified this)
        //Features: this function will not execute immediately, but return a new function after modifying this
        //Application scenario: event handling function, timer
        let newFn = fn.bind({ name: 'Hyk ' });
        console.log(newFn);
        newFn(50, 60);


        //4. this in the timer must point to window

        // Timer: a piece of code interval event execution setTimeout (a piece of code, interval time)

        //4.1 named function
        let test = function () {
            console.log('I'm a named function');
            console.log(this);
        };

        let newTest = test.bind({ name: 'Zhang San' })

        setTimeout(newTest, 3000);

        //4.2 anonymous functions
        setTimeout(function () {
            console.log('I am a function in the timer');
            console.log(this);
        }.bind({ name: 'Li Si' }), 2000);
    </script>

Function call() application scenario

 /* 
        1. Function up and down execution mode: dynamically modify this
            Note: the modified this can only be a reference type

        2.If the basic data type is written 
            string,number,boolean :  Customize and help us convert to the corresponding basic package type new String() Boolean() Number()
            undefined,null :
         */

        function fn() {
            console.log(this);

        };

        fn.call('str');//String
        fn.call(1);//Number
        fn.call(true);//Boolean

        //If undefined and null are passed, or not. The code will not report an error, nor will it help us modify this. It is still the original window
        fn.call(undefined);//Window
        fn.call(null);//Window
        fn.call();//Window
        fn.call(window);//Window

Object.prototype.toString.call() universal test data type

1.Object.prototype.toString() gets a fixed format string
2. Fixed format syntax of detection data type: object prototype. toString. call()
Get a fixed format string: [object data type]

 /* call Scenario: data type detection */

        //1. typeof data: detection data type 
        /* typeof Two data types cannot be detected: null and array will get object */

        console.log( typeof '123' )// 'string'
        console.log( typeof 123 )//'number'
        console.log( typeof true )//'boolean'
        console.log( typeof undefined )//'undefined'
        console.log( typeof null )//'object'
        console.log( typeof [10,20,30] )//'object'
        console.log( typeof function(){} )//'function'
        console.log( typeof {name:'123'} )//'object'

        //2. Object.prototype.toString(): get fixed format string 
        //"[object type]", where type is the type of the object
        //Detect fixed format syntax of data type: object prototype. toString. Call (data)
        
        console.log( Object.prototype.toString.call('123') )//[object String]
        console.log( Object.prototype.toString.call(123) )//[object Number]
        console.log( Object.prototype.toString.call(true) )//[object Boolean]
        console.log( Object.prototype.toString.call(undefined) )//[object Undefined]
        console.log( Object.prototype.toString.call(null) )//[object Null]
        console.log( Object.prototype.toString.call([10,20,30]) )//[object Array]
        console.log( Object.prototype.toString.call(function(){}) )//[object Function]
        console.log( Object.prototype.toString.call({name:'123'}) )//[object Object]
        

apply context call

        function fn(a,b){
            console.log(this)
            console.log(a+b)
        }

        fn(1,2)//Common function this - > window

        //(1) Function name Call (modified this, parameter 1, parameter 2,...)
        fn.call({name:'Zhang San'},10,20)
        //(2) Function name Apply (modified this, array / pseudo array)
        //When apply ing passes parameters, it will automatically traverse the array, and then pass parameters a = [30,40][0] b=[30,40][1] one by one in sequence
        fn.apply({name:'Li Si'},[30,40])
    </script>

arr.push. Application scenario of apply (arr, pseudo array): pseudo array to true array

<script>

 /* 
        Pseudo array: there are three elements of an array (subscript, element and length), but the array method cannot be used
            Pseudo arrays are essentially objects
            Pseudo arrays cannot use Array methods: the prototype of a pseudo Array points to the prototype of an object, not the prototype of an Array
*/
        let obj = {
            0: 10,
            1: 20,
            2: 30,
            3: 40,
            length: 4,//length cannot be omitted
        }
        console.log(obj[0]);

        //Convert the pseudo array to the real array arr.push, add elements to the back of the array, and return the length of the array
        let newArr = []
        let a = newArr.push(obj[0], obj[1], obj[2], obj[3])
        console.log(newArr)//[10, 20, 30, 40]
        console.log(a)//Array length 4

        // ES5: Context
        let newArr1 = []
        newArr1.push.apply(newArr1, obj)
        //The first parameter: newArr1. Originally, this is newArr. There is no need to modify this (equivalent to this unchanged)
        //The second parameter: obj with the help of the apply feature: automatically traverse the pseudo array / array and pass the parameters one by one (omitting the for loop)
        console.log(newArr1);

        // ES6 recommendation: arr.from (pseudo array) pseudo array to real array
        let arr = Array.from(obj)
        console.log(arr);
    </script>

Math.max.apply(Math, arr) application scenario: find the maximum value of the array

 <script>
        //Max array
        let arr = [10, 13, 12, 3, 14, 23, 32]

        // 1.arr.sort() array sorting parameter: callback function fixed syntax rote
        //     arr.sort(function (a, b) {
        //         return a - b / / from small to large
        //         return b - a / / sort from large to small
        //     })
        arr.sort(function (a, b) {
            return b - a
        })
        console.log(arr[0]);

        //2. Challenge arena thought
        let max = 0
        for (let i = 0; i < arr.length; i++) {
            if (arr[i] > max) {
                max = arr[i]
            }
        }
        console.log(max)

        // ES5:  Math.max.apply(Math, array name)
        //Function name Apply (modified this, array / pseudo array)
        //The first parameter Math: Math calls the method. This refers to math. There is no need to modify this (pass math, equivalent to this unchanged)
        //The second parameter arr: with the help of the characteristics of apply Automatically traverse the array / pseudo array and pass parameters one by one
        let max3 = Math.max.apply(Math, arr)
        console.log(max3);

        //ES6 (recommended):
        let max4 = Math.max(...arr)
        console.log(max4)
    </script>

bind context call

  function fn(a,b){
            console.log(this)
            console.log(a+b)
        }

        fn(1,2)//Common function this - > window

        //(1) Function name Call (modified this, parameter 1, parameter 2,...)
        fn.call({name:'Zhang San'},10,20)
        //(2) Function name Apply (modified this, array / pseudo array)
        //When apply ing passes parameters, it will automatically traverse the array, and then pass parameters a = [30,40][0] b=[30,40][1] one by one in sequence
        fn.apply({name:'Li Si'},[30,40])
        //(3) Function name Bind (modify this)
        //bind does not call the function immediately, but gets a new function after modifying this
        let newFn = fn.bind({name:'Wang Wu'})
        newFn(25,66)

bind() application scenario

The bind scenario is mainly used to modify functions that do not need to be executed immediately
//Event handling function, timer function

 //The bind scenario is mainly to modify 'functions that do not need to be executed immediately'
        //   Event handling function, timer function

        //1. this in the timer must be window
        let fn = function(){
            console.log( this )
        }
        //Modify this using bind
        let newFn = fn.bind({name:'666'})
        // fn(): call the function, and the result is the return value of the function
        // fn: value of the variable, and fetch the heap address stored in fn
        setTimeout( newFn ,3000)

        //The following is the same as the above: functions are data types, and syntax can be used directly like other data
        setTimeout(function(){
            console.log(this)
        }.bind({name:'Dry rice'}),3000)

3. Recursive function:

/*Higher order functions: self calling function, callback function, closure, recursion*/

What is a recursive function?: Function calls itself internally
*Note: you need to meet the conditions before recursion, otherwise it will lead to an endless loop
*Recursive functions are similar to loop functions

        //A function recursion
        // function fn(){
        //     console.log('ha ha ');
        //     fn();           
        // };

        // fn();

        //Two function recursion
        // function fn1(){
        //     console.log('ha ha ');
        //     fn2();
            
        // };

        // function fn2(){
        //     console.log('ha ha ');
        //     fn1();
            
        // };
        // fn2();


        //Requirements: write a function and print the monitor AI Kunge three times

        let i = 1;
        function fn(){
            console.log('study hard');
            i++;
            if(i <= 3){
                fn();
            };
            
            //Loop implementation
            // for(let i = 1;i<=3;i++){
            //     console.log('monitor AI Kun ');
                
            // };
        };
        fn();

Recursive application scenario:

2.1 light copy and deep copy

1. Shallow copy: the address is copied, and the modified copied data has an impact on the original data
       //Declare an object
        //Copy: copy a copy of the data stored in the object and assign it to other objects
        let obj = {
            name:'ikun',
            age:30,
            hobby:['lecture','student','study'],
            friend:{
                name:'friend',
                sex:'male'
            }
        }

        //Shallow copy: the copy is the address
        let obj1 = obj
        //Due to shallow copy, the copy is the address. Therefore, after modifying the copied data, the original data will also change
        obj1.hobby = 'delicious food'
        console.log(obj1,obj)
2. Deep copy: data is copied, and the modified copied data has no impact on the original data
  let obj = {
            name:'ikun',
            age:30,
            hobby:['lecture','student','study'],
            friend:{
                name:'friend',
                sex:'male'
            }
        }  
        
        /* 
        (1)Traverse obj and add all attributes to newObj
        (2)If obj[key] is a reference type (array, object), the address cannot be copied directly
            (2.1)Array: declare an empty array for newObj, then traverse obj[key], and add the elements inside to newObj[key]
            (2.2)Object: declare an empty object for newObj, then traverse obj[key], and add the inner elements to newObj[key]
        (3)If obj[key] is not a reference type, it is assigned directly. End recursion
        */

        function kaobei(newObj,obj){
            for(let key in obj){
                //Determine whether obj[key] is an array type
                if( obj[key] instanceof Array ){
                    //Declare an empty array and continue copying the data in the array
                    newObj[key] = []
                    kaobei(newObj[key],obj[key])
                }else if(obj[key] instanceof Object){
                    //Declare an empty object and continue copying the data in the array
                    newObj[key] = {}
                    kaobei(newObj[key],obj[key])
                }else{
                    newObj[key] = obj[key]
                }
            }
        }

        //Call the deep copy function
        let newObj = {}
        kaobei(newObj,obj)
        //Deep copy: modifying the copied data has no impact on the original data
        newObj.hobby[0] = '111'
        console.log( newObj,obj)
3. Realize deep copy with JSON conversion
/*   2.Deep copy can be implemented in two ways
            2.1 Recommended: json conversion
            2.2 Recursion:
*/
  let obj = {
            name:'ikun',
            age:30,
            hobby:['lecture','student','study'],
            friend:{
                name:'friend',
                sex:'male'
            }
        }    

        //(1) First, convert the js object into a json format string: json Stringify (js object)
        //When json converts js into json format string, the bottom layer will automatically copy it for you
        // let json = JSON.stringify(obj)
        // console.log( json )
        //(2) Then convert the json string just now into a js object: json Parse (json format)
        // let js = JSON.parse( json )

        // js.hobby = 'learning'
        // console.log( js,obj )

        //The above two processes can be simplified into one line of code
        let newObj = JSON.parse( JSON.stringify( obj ) )
        newObj.friend = 'puppy'
        console.log(newObj,obj)
4. Traverse the dom tree
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <style>
      * {
        padding: 0;
        margin: 0;
      }

      .menu p {
        width: 100px;
        border: 3px solid;
        margin: 5px;
      }

      .menu > div p {
        margin-left: 10px;
        border-color: red;
      }

      .menu > div > div p {
        margin-left: 20px;
        border-color: green;
      }

      .menu > div > div > div p {
        margin-left: 30px;
        border-color: yellow;
      }
    </style>
  </head>
  <body>
    <div class="menu">
      <!-- <div>
        <p>First level menu</p>
        <div>
          <p>Second level menu</p>
          <div>
            <p>Third level menu</p>
          </div>
        </div>
      </div> -->
    </div>
    <script>
      //The server returns an indeterminate data structure involving multiple array nesting
      let arr = [
        {
          type: 'electronic product',
          data: [
            {
              type: 'mobile phone',
              data: ['iPhone mobile phone', 'Mi phones', 'Huawei mobile phone']
            },
            {
              type: 'Flat',
              data: ['iPad', 'Flat millet', 'Tablet Huawei']
            },
            {
              type: 'Intelligent Watch',
              data: []
            }
          ]
        },
        {
          type: 'Living home',
          data: [
            {
              type: 'sofa',
              data: ['Leather sofa', 'Cloth sofa']
            },
            {
              type: 'chair',
              data: ['Dining chair', 'Computer chair', 'Office chair', 'Leisure chair']
            },
            {
              type: 'Table',
              data: ['desk']
            }
          ]
        },
        {
          type: 'snacks',
          data: [
            {
              type: 'Fruits',
              data: []
            },
            {
              type: 'Coffee',
              data: ['Nescafe']
            }
          ]
        }
      ]
      
      //arr: Data father: parent box
      function addElement(arr,father){
        //Traverse the array, generate div > P and add it to the parent element
        for(let i = 0;i<arr.length;i++){
            //(1) Create empty label
            let div = document.createElement('div')
            //(2) Set content
            div.innerHTML = `<p>${arr[i].type || arr[i]}</p>`
            //(3) Add to parent box
            father.appendChild(div)
            //If the menu still has data, it indicates that there are submenus, you need to continue to traverse and add
            if( arr[i].data ){
                addElement(arr[i].data,div)
            }
        }
      }

      let menu = document.querySelector('.menu')
      //Call function
      addElement(arr,menu)

    </script>
  </body>
</html>

4. Closure:

  • 1. What is a closure: a closure is a function that can access internal variables of other functions
  • 2. The function of closure: solving variable pollution
        function fn(){
            let a = 1
            //In the fn1 function, variables inside other functions fn are accessed. fn1 + a form closure
            function fn1(){
                console.log(a)
            }
            fn1()
        }
        fn()
        
        function test(){
            let num = 1
           
            setTimeout( function(){
                console.log(num)  
            },2000)
        }

        test()

Closure scenario:

    <script>
        /* 
        1.What is a closure?
            1.1 A closure is a function that accesses internal variables of other functions
            1.2 Closure = combination of function + context reference
            Conclusion: there are two conditions for the formation of closures, one of which is indispensable. (1) Function (2) accessing internal variables of other functions

        2.Closure effect: variable pollution
            * Most of the late closures are usually in the callback function
        */    
       
        //Get element
        let input = document.querySelector('input')
        let button = document.querySelector('button')

        
        button.onclick = function(){
            //There is a variable to store search results
            let str = '6666'
            //Simulate network request: get search results after 2 seconds
            setTimeout(function(){
                alert(`The search is over. The search result is ${str}`)
            },2000)
        }
    </script>

5. Summary:

5.1 three directions of this

  1. Global function: function name () -------------- > this points to window
  1. Object method: object name Method name () ---- -- > this points to the object
  2. Constructor: new function name () ------------- > this points to the empty object created by new

5.2call, apply and bind differences

  • The same point: both modify the function this point
  • difference
    • The parameter transfer methods are different: call is used for a single parameter and apply is used for multiple parameters
    • The execution mechanism is different: call and apply will be executed immediately, and bind will not be executed immediately
      • call and apply are modified once
      • bind; Once modified, it is valid for life

5.3 closure

  • What is a closure: both of the following answers are OK
    • A closure is a function that accesses internal variables of other functions
    • Closures are function + context code combinations
  • Closure function: solving variable pollution

5.4 recursion

  • What is recursion: a function calls itself internally
  • Recursive scenario
    • Deep copy
    • Traversing dom tree

Keywords: Javascript ECMAScript

Added by wombatee on Mon, 27 Dec 2021 08:08:34 +0200