JavaScript summary 7.0—The most comprehensive and understandable explanation of this

    The appearance of this can make the front-end code more readable and flexible to a certain extent, especially in the encapsulation of triggering events and objects and classes. Although we all know that this points to the problem is very important, it is difficult to really explain it clearly . So record my step-by-step understanding of this since I learned the front-end, I hope it will be helpful to everyone

    this binding rule

    1 default binding

    1.Global Execution Environment
    Whether in strict mode or not, in the global execution environment (outside any function body) this refers to the global object window

    'use strict'
    console.log(this); //window
    


    2.Ordinary functions are called independently
    In non-strict mode, this inside the function points to window

    function f1(){
       return this;
    }
    console.log(f1()===window);//true
    

    In strict mode, this points to undefined

        function f1() {
        'use strict';
        return this;
      }
      console.log(f1()); //undefined
    

    PS: Subsequent code defaults to non-strict mode


    3.The function is defined in the object, but called independently
    Independent function call: call fn() directly, there is no object such as obj.fn() in front of the function fn and there is no call, apply, bind behind to change the point of this example 1:

    var obj = {
     bar: function () {
       console. log(this);
     },
       };
    
       var baz = obj. bar;
       baz(); //window
       obj.bar(); // non-independent function call, this points to the boj object
    

    example 2:

    function foo(fn){
     fn()
    }
      var obj = {
     bar: function () {
       console.log(this); //window
     },
       };
       foo(obj. bar)
       //this still points to window, and obj.bar returns a function, which actually calls fn() in the foo function. There is no implicit binding on the left and no explicit binding such as call on the right. It is an independent function call. point to window
    


    4.Execute the function immediately
    Immediately execute the function this to point to the global window

     var name = 'a';
      var obj = {
    name: 'b',
    func: (function () {
      console.log(this.name,this); //a,window
    })(),
      };
    


    5.Closure this problem
    The information on the Internet almost all say that the this of the closure function returns window, but I don’t agree with it. The this point of the closure will also change in different code environments. The following is the code practice verification. When closing the closure, don’t blindly think that this points to window, only by analyzing the execution of the code can you draw the correct conclusion

    //The closure of the nested function inside the function
    function foo() {
     function bar() {
       console. log(this);
     }
     return bar;
    }   
      var fn = foo();
      fn(); // this points to window, which is equivalent to an independent function call
       var obj = {
        eating: fn,
       };
       obj.eating(); // Implicit binding, this points to the obj object
    


    6.Higher order functions

     function test1() {
    console.log(this);
      }
    
      function test2() {
    console.log(this);
    test1();
      }
    
      function test3() {
    console.log(this);
    test2();
      }
      test3();
    //this all points to window, because the calls of the three functions are essentially independent function calls
    

    2. Implicit binding

    Implicit binding means calling a function through an object: object.fn() // The object object will be bound to this in the fn function by the js engine

    conditions for implicit binding: there is a reference to the function inside the calling object (eg a property whose value is a function) It is through this reference that this is indirectly bound to this object. If there is no such reference, an error that the function cannot be found will be reported when the function is called
    example1:

    function foo() {
     console. log(this);
       }
       var obj = {
        bar: foo,
       };
     obj.bar();//obj object
    

    example2:

     var obj1 = {
      name: "obj1",
      foo: function() {
    console.log(this)
      }
    }
    var obj2 = {
      name: "obj2",
      bar: obj1.foo
    }
    obj2.bar() //obj2
    ////obj2.bar returns a function that prints this, implicitly bound to obj2
    

    example3:

    function foo() {
    console.log(this); // obj2
      }
      var obj1 = {
    name: 'obj1',
    foo: foo,
    obj2: {
      name: 'obj2',
      foo: foo,
    },
      };
      obj1.obj2.foo(); // obj1.obj2 returns the obj2 object, and the foo function is called through obj1
     //Implicit binding this points to the technique: look at the nearest left binding object when the function is called
    


    3. Display bindings

    1. Using call or apply (apply is an array, call is a parameter list) to explicitly bind the object pointed to by this is explicit binding

      function foo() {
      console.log(this);
       }
      
      foo.call({ name: 'fang' }); //{name:'fang'}object
      foo.apply(window); //window
      foo.apply('ddl'); //String {'ddl'}
      


    2.bind binding
    If you want a function to always be explicitly bound to an object, you can use the bind method (return a new binding function without calling this function)

     function foo() {
        console.log(this);
      }
      var obj = {
        name: 'fang',
      };
      var test = foo.bind(obj);
      test(); //obj object
    


    4. Binding of built-in functions

    1.setTimeout
    By default, the this of the timer points to window

    setTimeout(function() {
    console.log(this) // window
    }, 2000)
    


    2.Monitor click and other events
    When a function is used as an event handler, its this points to the element that triggered the event
    NOTE:Some browsers don't follow this convention when dynamically adding listeners using functions other than addEventListener

    var btn = document.querySelector("button")
    btn.addEventListener("click", function() {
      console.log(this) //button
    })
    


    3.The second parameter after the array forEach/map/filter/find is passed into the function is the object pointed to by this

    var names = ["a", "b", "c"]
    names.forEach(function(item) {
      console.log(this) //window
    })
    names.map(function(item) {
      console.log( this) //String {'testtest'}
    }, "testtest")
    


    5. new binding

    When a function is used as a constructor (using the new keyword), its this is bound to the new object being constructed

    function Person(name) {
      this.name = name
      console.log(this); 
    }
    var p1 = new Person("fang")//Person {name: 'fang'}
    var p2 = new Person("xiao")//Person {name: 'xiao'}
    

    If the return value of the constructor is a reference type object or array, the default object bound to this is discarded, and the return value in the constructor is returned

    function C(){
      this.a = 37;
    }
    var o = new C();
    console.log(o.a); // 37
    
    function C2(){
      this.a = 37;
      return {a:38};
    }
    
    var o2 = new C2();
    console.log(o2.a); // 38,return{a:38};
    
    function C3(){
      this.a = 37;
      return [1,2,3];
    }
    var o3 = new C2();
    console.log(o3); // [1,2,3]
    

    6. The priority of different binding rules

    new binding > explicit binding (bind takes precedence over apply/call) > implicit binding (obj.foo()) > default binding (independent function call)
    PS: The priority of new binding is higher than that of bind, and new binding, call and apply are not allowed to be used at the same time

    Code test:
    1. bind is higher than the default binding

     function foo() {
    console.log(this);  //String {'abc'}
      }
      var obj = {
    foo: bar,
      };
      var test = obj.foo.bind('cba');
      test();
      //Equivalent to
      //var bar = foo.bind('abc');
      //obj.foo();
    


    2.new has higher priority than bind

     function foo() {
    console.log( this)
      }
      var bindFn = foo.bind("aaa")
      bindFn() //String {'aaa'}
      new bindFn() //foo {}
    


    3. bind has higher priority than apply/call

    function foo() {
    console.log( this) //String {'aaa'}
      }
      var bindFn = foo.bind("aaa")
      bindFn.call("bbb")
    


    7. Special case of this binding rule

    1. If in the display binding apply/call/bind, when null or undefined is passed in, the display binding will be invalid and this will be automatically bound to the global object

      function foo() {
      console.log(this);
      }
      foo.apply(null); //window
      foo.apply('abc'); //abc
      foo.apply({}); //{}
      foo.apply(undefined); //window
      var bar = foo.bind(null);
      bar(); //window
      
    2. Indirect function reference problem (obj2.foo = obj1.foo)
      The result of the assignment (obj2.foo = obj1.foo) is the foo function. After the assignment, the foo function is called directly (independent function call), using the default binding this to point to window

      var obj1 = {
      name: 'obj1',
      foo: function () {
      console.log(this);
      },
      };
      
      var obj2 = {
      name: 'obj2',
      };
      // obj2.foo = obj1.foo
      // obj2.foo() //{name: 'obj2', foo: ƒ}
      (obj2.foo = obj1.foo)(); //window
      


    this of the arrow function

    The arrow function determines this according to the outer scope. It does not use the standard rules of this mentioned above. It is only related to the location and environment of the arrow function. In the global code, this will be set to the global object



    1. If this is passed to call, bind, or apply to invoke an arrow function, it will be ignored.
    var foo = () => {
      console.log(this)
    }
    foo()
    var obj = {foo: foo}
    obj.foo()
    foo.call("abc")
    foo.bind(123)()
    //The printed this is all window, because the arrow function uses call, apply, bind to display binding and obj.foo() implicit binding, etc. will be invalid
    


    var obj = {
    bar: function () {
      var x = () => console.log(this);
      return x;
        },
      };
      var fn = obj.bar()(); //this point to obj
    //The environment where x is located is in the bar function, so the this of the arrow function points to the this of the bar function, and the this of the bar function points to obj through the implicit binding of obj
    

    But pay attention to the following situation, if you just refer to the method of obj without calling it, then after calling the arrow function globally, this points to window. Because fn2 is the bar function, the this of bar points to window through fn2()() independent function call

    var fn2 = obj. bar;
    fn2()() //this points to window
    


    class of this

    Strict mode is always inside a class, and like other ordinary functions, the value of this in class methods depends on how they are called

    static keyword is used to define a static method of a class. Calling a static method does not need to instantiate the class and cannot call a static method through a class instance. They are just properties of the class itself.

    class Person {
         constructor(name, age) {
           this.name = name;
         }
         // instance method
         running () {
           console.log(this.name + 'running');
         }
         //Static methods can only be properties of the class itself
         static displayName = 'Existence is reasonable';
         static add(a, b) {
           return a + b;
         }
       }
       var p1 = new Person('fang');
       var p2 = new Person('Abaaaba');
       console.log(p1.displayName); //undefined
       console.log(Person.displayName); //Existence is reasonable
       console.log(Person.add(1, 2)); //3
       p1.running(); //fang running
       p2.running(); //Abaaba running
    


    Analysis of this comprehensive question

    Example1 :

    var name = "window";
    var person = {
      name: "person",
      sayName: function () {
    console.log(this.name);
      }
    };
    function sayName() {
       var foo = person. sayName;
       foo(); // window:foo is the sayName function, without implicit binding on the left and explicit binding on the right, it is an independent function call
       person.sayName(); // person: implicitly bound
       (person.sayName)(); // person: implicit call
       (b = person. sayName)();
       // special case of window, this binding rules: indirect function reference, assignment expression (independent function call)
    }
      sayName();
    


    Example2 :

    var name = 'window'
    var obj1 = {
      name: 'obj1',
      foo1: function () {
    console.log(this.name)
      },
      foo2: () => console.log(this.name),
      foo3: function () {
    return function () {
      console.log(this.name)
    }
      },
      foo4: function () {
      return () => {
      console.log(this.name)
        }
      }
    }
    var obj2 = { name: 'obj2' }
    obj1.foo1(); // obj1 (implicit binding)
    obj1.foo1.call(obj2); // obj2 (display binding priority is greater than implicit binding), that is, when there are rules on both sides of the function, look at the display binding rules on the right
    
    obj1.foo2(); // window, foo2 is an arrow function, this points to the this of the upper scope obj1, that is, the global window
    obj1.foo2.call(obj2); // window, call fails in arrow function
    
    obj1. foo3()();
    // window (independent function call), obj1.foo3() returns the function ƒ () {console.log(this.name)}, then direct independent function call
    obj1.foo3.call(obj2)();
     // window (independent function call), obj1.foo3.call(obj2) changes the this point of foo3, but returns the function that prints this.name, and then directly adds parentheses to make an independent function call
    obj1.foo3().call(obj2);
    // obj2, call the returned function using explicit binding, this points to the explicitly bound obj2
    
    obj1.foo4()(); // obj1 (the arrow function does not bind this, the this of the upper scope foo4 is obj1)
    obj1.foo4.call(obj2)(); // obj2 (this of the upper scope foo4 is explicitly bound to obj2)
    obj1.foo4().call(obj2);
     // obj1, obj1.foo4() returns an arrow function that cannot be called. According to the this of the upper scope foo4, it points to obj1
    


    Example3 :
    When doing the questions, pay attention to see which function is bound by call, apply, etc.

     var name = 'window';
      function Person(name) {
    this.name = name;
    this.obj = {
      name: 'obj',
      foo1: function () {
    console.log(this.name);
      },
      foo2: () => console.log(this.name),
      foo3: function () {
    return function () {
      console.log(this.name);
    };
      },
      foo4: function () {
    return () => {
      console.log(this.name);
    };
      },
    };
      }
      var person1 = new Person('person1');
      var person2 = new Person('person2');
    
       person1.obj.foo1(); // implicit binding: obj
       person1.obj.foo1.call(person2); // explicit binding: person2
    
       person1. obj. foo2();
       // foo2 is an arrow function, this points to search in the upper scope, that is, this of obj points to: person1
       person1.obj.foo2.call(person2); // call fails, search in the upper scope: person1
    
       person1.obj.foo3()();
       // window (independent function call), person1.obj.foo3() returns the function that prints the name and calls it directly
       person1.obj.foo3.call(person2)();
       // window (independent function call), the call changes the this point of foo3, not the this point of the return function
       person1.obj.foo3().call(person2);
       // Explicit binding: person2, call changes the this point of the returned function
    
       person1.obj.foo4()();
       //obj, the arrow function finds that the this of the upper scope foo4 points to obj
       person1.obj.foo4.call(person2)();
    //The arrow function finds the this point of foo4 in the upper scope and displays the binding as: person2
       person1.obj.foo4().call(person2);
       // Upper scope search: obj, call cannot change the this of the arrow function
    

    Popular posts from this blog

    大学资料分享——广工计院各个科目实验报告、课设及期末复习资料!!

    Win10 远程计算机或设备将不接受连接

    JAVA Traffic Signal Light Course Design (Source Code + Report + Video Demonstration)

    Implementation of Ajax Interceptor