This problem is almost a platitude of the problem, in fact, really ask themselves is also very vague, today taking advantage of the goddess festival day thoroughly understand this problem, forever.

When a function object is called, an active object is created. First, each parameter and argument of the function are added as properties and values of the active object. Add variables and functions that are declared in the function body, and also add attributes to the activity (when entering the function execution environment, the value is not assigned, so the value is undefined, which is the pre-declaration mechanism of JS).

  1. This four scenarios are defeated one by one

    Let me give you two tips before we go to war

    • It is only when a function is called (the runtime) that the this reference within the function is determined. Since this and arguments are special variables in a function, they can only be retrieved when the function is called, and a search for these variables will be performed in the live object scope
    • To determine what this refers to in a function, you must first find where the function was called.
    • First: when called as a method on an object, this refers to the object (javascript:void(0);).
      var obj ={
          a:1.getA:function(){
              console.log(this===obj)  // true
              console.log(this.a) / / 1}}; obj.getA();Copy the code
      var a =1 
      function test() {
          console.log(this.a)
      }
      var obj ={
          a:2,
          test
      }
      obj.test()  / / 2
      Copy the code
      var a = 1
      function test() {
          console.log(this.a)
      }
      var obj = {
              a: 2,
              test
          }
      var obj0 = {
              a: 3,
              obj
          }
      obj0.obj.test() / / 2
      Copy the code

      Even in this cascading form, the result is the same, with this in test() reporting only to the immediate boss (the caller obj). Here’s another example of a synthesis point:

      var a = 1 
      function test() {
          console.log(this.a)
      }
      var obj = {
          a: 2,
          test
      }
      var testCopy = obj.test
      testCopy()    //  1 
      Copy the code

      You might think it’s still obj.test(), but it’s not. This always refers to the object that last called it

    • Second: as a normal function call, this always refers to the global object Window
      console.log(this)  // window
      window.name = "globalName" 
      var getName =function(){
          return this.name
      }
      console.log(getName());   // globalName 
      Copy the code
    • Constructor calls. When a function is called with the new operator, the function always returns an object. Normally, this in the constructor refers to the object returned

      When a function is called as a constructor it has the following characteristics:

      A new object is created; The new object is passed to the constructor as this, which means that the new object is the context of the constructor function; If there is no explicit return statement, the new object is implicitly returned and becomes the constructor’s value

      • var  a = 1
        function test(a) {
            this.a =a
        }
        var b = new test(2)
        console.log(b.a)
        Copy the code

        The new operation produces an empty object and then a pointer to this, which points to the object; When the constructor is run, the object passes its derivatives as this, which is equivalent to “{}. A =a” adding attributes to the object and then paying b

      • var MyClass = function () {
            this.name = "class";
            return {
                name: "other"}}var obj = new MyClass();
        console.log(obj.name); // other
        Copy the code

        If there is no explicit return statement, the new object will be returned implicitly, but if the constructor explicitly returns an object, the result will return that object, not this

    • Function.prototype.call or function.prototype. apply and function.prototype. bind

      If you look at some of the forms above, you might think that I hate this mess and call this call that call, and I want to make my own decisions, my own life, my own code. Sure, no problem!!

      • Call and apply work the same way, only in the form of arguments passed in.

        • Apply takes two arguments. The first argument points to the this object in the function body, and the second argument is a set with an underlying index. This set can be an array or an array of classes.
        • Call takes variable arguments. Just like apply, the first argument also refers to this in the function body. From the second argument, each argument is passed to the function
        var test =function(a,b,c){
            console.log([a,b,c])
        }
        // The first argument passed in is null. This in the function body points to the default host object, or window in the browser
        test.apply(null[1.2.3]);  / / [1, 2, 3]
        test.call(null.1.2.3)   / / [1, 2, 3]
        Copy the code
      • Call and apply change the this reference

        var obj1 = {name:"obj1"};
        var obj2 = {name:"obj2"};
        window.name = "window"
        var getName = function () {
            console.log(this.name)
        }
        getName();   // window
        getName.call(obj1); //obj1
        getName.call(obj2)  // obj2
        Copy the code
      • Common methods for apply and call

        • Verify array (if toString() has not been overridden)

          function isArray(obj) {
              return Object.prototype.toString.call(obj) === '[object Array]';
          }
          Copy the code
        • Methods that make class arrays have arrays (e.g. arguments objects, retrieved document nodes, etc.) do not have array methods

          [].slice.apply(arguments); 
          / / or
          Array.prototype.slice. Apply (argument);Copy the code
      • The bind method changes fn’s this to the desired result in advance and prepares the corresponding parameter values for later use. In other words, bind can also change the direction of this, but unlike apply and call, it does not execute this immediately.

      • Foo. Bind ({a:1}) does not. The result is a new function whose this is bound to the first argument, meaning the new function is not executed.

        function foo(){
            return this;
        }
        var f1=foo.call({a:1});     
        var f2=foo.apply({a:2});    
        var f3=foo.bind({a:1});
        
        console.log(f1);        //{a:1}
        console.log(f2);        //{a:2}
        console.log(f3);        //function foo(){
                                // return this;
                                / /}
        console.log(foo());     / / the window object
        console.log(f3());      //{a: 1}
        
        Copy the code
      • The main difference between bind and apply and call is that bind does not call immediately

        var tempFn = fn.bind(obj, 1.2);
        tempFn();
        
        Copy the code

        The first line of code simply changes fn’s this to obj and passes fn two arguments, 1 and 2, but does not call fn. Bind returns a value, tempFn, that is the result of changing fn’s this.

  2. One more

    There’s another way to do this and don’t forget the Es6 arrow function, guess what the bottom result is

    var a =1
    var test = () = > {
            console.log(this.a)
        }
    var obj = {
            a: 2,
            test
        }
    obj.test() / / 1
    Copy the code

    Here’s our first tip: “The reference to this in a function is determined only when the function is called.” Now the word function needs to be modified to become a normal function (non-arrow function) to distinguish it from arrow function. The arrow function this is defined when the function is defined. Its this refers to its outer scope this.