preface

  • This article will take about 20 minutes \color{red}{20 minutes}
  • This article tells about:
      1. Several cases of This
      1. Distinguish the executor in different cases
          1. In event binding
          1. Normal method executing
          1. Constructor executing
          1. Arrow function
      1. The difference between xxx.xxx() and XXX ().xxx(
      1. Manually adjust the three methods to which this refers
          1. Call method details
          1. The execution of a call
          1. The execution of multiple calls in succession
          1. Implement a call method
          1. The apply method
          1. Bind method in detail
          1. Implement a bind method
          1. The event object
  • If you have any questions, please leave a message to me. I will reply when I see it. If I can’t solve it, we can also discuss and learn together. If you think there is any mistake, please kindly comment and correct me. Thank you very much. I hope to learn and make progress together with you in the future.
  • The next article will be updated as soon as possible, and the already written article will be modified intermittently in the future as understanding deepens or illustrations are added.
  • If you find this article helpful, please give it a thumbs-up. Thank you!
  • Welcome to reprint, please indicate the source.

This

This:

  1. In the global context This refers to the window
  2. A block-level context does not have its own This; its This inherits from the context’s This.
  3. In the private context of a function, the case for This can vary
  4. This is not the execution context (EC is the execution context,)This is the execution body
  5. This is always an object data type valueThis is the wrapper class for the value of the current base datatype (e.g., new Number(10)), except for null and undefined.

How to distinguish execution subjects:

  • 1. Event binding:

    • In event binding, giveThe elementWhen the event behavior is triggered, the method executes, and the method is bound to the event behaviorThis is the current element itself
      • DOM2 event binding in IE6~8 based on the attachEvent method, event trigger, method This is the window instead of the element itself.
        // Event binding DOM0
        let body = document.body;
        body.onclick = function(){
            // The event is fired, the method is executed, and this is body
            console.log(this);//BODY
        }
    
        // Event binding DOM2
        // If this method is bound to the event behavior of the current element, this is the body
        body.addEventListener('click'.function(){
            console.log(this);//BODY
        });
        // DOM2 event binding in Internet Explorer 6 to 8
        body.addEvent('click'.function(){
            console.log(this);//WINDOW
        });
    Copy the code

  • 2. Common method execution:

    • [including self-executing function execution, ordinary function execution, object member access call method execution, etc.]

      • A 'point':This is whoever comes before the dot
      • No 'dot':That means the function has no execution body, so This isWindow [in non-strict mode]orUndefined [in strict mode]
        • Self-executing functionThis is usually window or undefined
        • The callback function}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
    • ‘use strict’ Enables strict mode

    • Who is This in This function? It doesn’t matter where it’s executed, it doesn’t matter where it’s defined

    • The parent context of a function depends on what the function defines there

            // Self-executing function
            (function(){
                console.log(this);//window
                //This is window or undefined}) ();/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
            
            let obj = {
                fn: (function(){
                    console.log(this);//window
                    return function(){}; }) ()// Assign the return value of the self-executing function to obj.fn
            }
            / / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
            
            function func(){
                console.log(this);
            }
            let obj = {
                func:func// The property named func is the address of the func function
            };
            func();/ / This is a window
            obj.func();/ / This is obj
            / / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
            
            [].silce();
            [].silce: member access is not implemented
            // Then execute the slice method
            // This in slice is the current empty array (instance)
            / / = = = = = = = = = = = = = = = = = = = = = = = = = = = =
            
            Array.prototype.slice();Slice = array.prototype. slice = array.prototype. slice = array.prototype. slice = array.prototype. slice
            // Execute the slice method with this as array. prototype
            / / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
            
            [].__proto__.slice();
            //[].__proto__===Array.prototype
            // The slice method executes this: array.prototype
            // The prototype chain of an instance corresponds to the prototype of its class
            / / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
            
            function func(){
                / / this is a window
                console.log(this);
            }
            document.body.onclick = function(){
                // The event is emitted, the method is executed, and this in the method is the body
                console.log(this);//BODY
                func();//window
            }
    Copy the code

  • 3. Constructor execution (NEW XXX) :THIS in the constructor body is an instance of the current class

    • When the constructor executes, it executes the function as if it were a normal function and creates an instance object inside of it while executing, with this pointing to the instance object
      • The THIS in the constructor body isConstructor executionTHIS. XXX = XXX is a private property set to the current instance.
          function func(){
              this.name = 'F';
              console.log(this);//func{name:'F'}
              // The constructor executes, with this in the function body pointing to the created instance object
          };
          let f = new func;
          console.log(f);//func{name:'F'}
      Copy the code
              
          func.prototype.getName = function getName(){
              // THIS is not always an instance of a prototypical method. It depends on how it is executed
              console.log(this);
          };
      
          f.getName();//this=>f
          f.__proto__.getName();//this=>f.__proto__
          func.prototype.getName();//this=>func.prototype
      
      Copy the code

  • 4.Arrow function(Arrow function)【ES6】

    • Provided in ES6Arrow functions do not have their own this.Its this is inherited from the context of this
      • Even if the method is a little bit ahead of execution, all the rules for encountering arrow functions are broken because arrow functions don’t have their own this
      • Arrow functions don’t have their own this, even thoughForcing change won't help eitherCall () 】 【.
    • Therefore, it is not recommended to use the arrow function arbitrarily.
          /* Ordinary function execution: form private context (and Ao) initializer scope chain initializer this initializer argument assignment variable improves code execution */
          / / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
           /* Arrow function execution: form private context (and Ao) initializes scoped chain parameter assignment variables to promote code execution
           let obj = {
               func:function(){
                   console.log(this);
               },
               sum:() = >{
                   console.log(this); }}; obj.func();//this=>obj
           obj.sum();//this=> this in context EC(G),this=>window
      Copy the code
        
           let obj = {
               i:0.func(){
                   let _this = this;
                   console.log(this);
                   / / this = > obj {I: 0, func: ƒ}
                   setTimeout(function(){
                       // Anonymous callback function Normally this is window
                       this.i++;//this=>window
                       console.log(this); / / this = > obj {I: 0, func: ƒ}
                       // if you want to use obj for this
                       /* Option 1 */
                       _this.i++;
                       console.log(_this);/ / obj {I = 0, func ()}
                   },1000); }}; obj.func();Copy the code
        /* Option 2 */
           let obj = {
               i:0./ / I = 0 obj
               //func:function(){}相当于↓
               func(){
                   //this=>obj
                   setTimeout(function(){
                      this.i++;//this=>obj
                       console.log(this);
                   }.bind(this),1000);
                   // Preprocess this as an outer function based on bind}}; obj.func();Copy the code
        /* Option 3 */
           let obj = {
               i:0./ / I = 0 obj
               //func:function(){}相当于↓
               func(){
                   //this=>obj
                   setTimeout(() = >{
                      this.i++;//this=>obj
                       console.log(this);
                   },1000);
                   // Use the arrow function, since it does not have its own this, this is the context of this, which is obj.}}; obj.func();Copy the code

  • The difference between XXX () and XXX ().xxx() :

    • XXX. XXX ()The __proto__ prototype chain lookup mechanism is used to find the method with parentheses first, and then execute the method first, while doing some operations on the previous instance in the process. And in front of if XXX.XXX.XXX. XXX are from left to right a layer a layer a level of search
    • XXX ().xxx() executes the previous method and then calls the later method with the return value.

  • 5. Manually adjust this function to point to call/apply/bind

    • Can be based on"Call/apply/bind"Force manually changing the this pointer in a function
      • These three modes are very direct and very violent(For the first three cases above, after the three methods are used to modify them manually, the “this” point will prevail.)
    1. 【call】 : [0~ multiple parameters]

      1. format: [r]. The function call ((context), params1, params2…). ;
        • The call method is called by a function,The call method is executed first, and then something is done to the current function during execution.[function] as an instance of the function built-in class, you can use the __proto__ prototype chain lookup mechanism to find the call method in function. Prototype object, and execute the call method.]
        • When the call method is executed, the operation to the current function is:
          1. Change this to the first parameter in the call method [conctxt]. The rest of the parameters are params1,params2…. Are arguments to be passed when the current function is executed.
          2. The current function is then executed, and finally the return value of the function is received as the return value of the call method
      2. The first argument to the call method
        • If null/undefined is passed, in non-strict mode this points to the window Built-in class if a primitive type value is passed
        • In strict mode, whoever is passed this is who, not passed is undefined
          var person = {
          fullName: function(city, country) {
              return this.firstName + "" + this.lastName + "," + city + ","+ country; }}var person1 = {
          firstName:"Bill".lastName: "Gates"
          }
          var person2 = {
          firstName:"Steve".lastName: "Jobs"
          }
          var x = person.fullName.call(person1, "Seatle"."USA"); //Bill Gates,Seatle,USA
          // The first argument is to call this, and the following argument is to call the current function to execute after the call method is executed.
      Copy the code
    • 【 A call: 】The function before call is finally executed, and when the function is executed, the this pointer becomes the first argument, and the remaining arguments are passed in as arguments to the function
    • 【N multiple calls: 】 Function. Prototype finds the call method and only executes the last parenthesized call. It just exists as this to perform the last call
      • [execution process] :(combined with the serial call analysis in the following example)
        1. The last call is executed first, with the preceding “this” as the function to be executed, the “this” as the first argument, and the remaining arguments passed in as arguments to the function. 】
        2. And the final result of this stringJust a callEquivalent to call.call(parameter 1, parameter 2…); So when the last call is executed, the previous function is executed, and a new call is executed
        3. In this call, this is the first argument passed to the first call execution. After the call execution, this of the previous function is specified as the first of the remaining arguments, and the remaining arguments are used for its execution
          function A(x,y){
              let res = x+y;
              console.log(res,this.name);
          }
      
          function B(x,y){
              let res = x+y;
              console.log(res,this.name);
          }
          / / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
          B.call(A,10.20);/ / 30, A
          // Finally B is executed, and when B is executed, the this pointer changes to A, and the remaining arguments are passed in as arguments to the function execution
          //【 see A.B(10,20);】
          / / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
          B.call.call.call.call.call.call(A,20.10);
          Call (b.call.call.call); call (b.call.call.call); call (b.call.call.call); So this line of code is actually equivalent to call.call(A,20,10);
          / / call. The call (A, 20, 10); When the first call is complete, execute the previous function, i.e. the new call. This is A, and the parameter passed in is (20,10) => when the first call is complete, the function is also executed.
          // This is A when the second call is executed, change this to 20, and pass in 10. When 20 is called, it is actually new and becomes a wrapper class Number.
          // execute A, pass in 10, the second parameter is undefined. The sum is NaN. This in A is (20), where there is no name attribute, return undefined.
          // The final result is NaN, undefined
          / / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
          Function.prototype.call(A,60.50);Prototype is an anonymous empty Function that executes without any processing or output
          Function.prototype.call.call(A,60.50);
          / / the Function prototype. Call. And the biggest all the call. The call. The call. The call. There is no difference, and all you find is the Call method itself
          A.call (60,50)=>Number(60).a (50)
          // Same as multiple calls
      Copy the code

      1. Simulate a CALL method with native JS【手撕call】

        1. Fn () => Obj =>obj.fn() => Fn function as a member of the obj attribute value
        2. obj.fn = fn; Obj.fn (); Call this function as a member of the object to be changed, and then execute the function based on the object’s member access.
        3. Processing of other parameters and so on….
        // Initial version
        // This version is not good, because adding member attributes to an object may change the existing attributes
            Function.prototype.call = function call(context,... params){
                //context -> this in the function to be changed
                //params -> The last argument information to be passed to the function
                //this -> the function to process
        
                context = context == null?window:context;
                // if the value is null, the value is null.
                // If it is empty, change to window; if it is not empty, change to the specified context
                let result;
                context['fn'] = this;// Take the function to be executed as a member value of the object
                result = context['fn'] (... params);[object.[member function](); To execute the function
                // This is the object in the function (passing the argument to the function and receiving the return value)
                delete context['fn'];
                return result;
            }
        Copy the code
        // Optimized version
            Function.prototype.call = function call(context,... params){
                //context -> this in the function to be changed
                //params -> The last argument information to be passed to the function
                //this -> the function to process
                
                context = context == null?window:context;
                // if the value is null, the value is null.
                // If it is empty, change to window; if it is not empty, change to the specified context
                Context must be an object
                let contextType = typeof context;
                if(!/^(object|function)$/i.test(contextType)){
                   // If the type is neither object nor function, convert it to an object or "wrapper class"
                   //context.constructor: The class to which the current value belongs
                   //context = new context.constructor(context); // This method is not suitable for BigInt and Symbol.
                   context = Objext(context);// omnipotent processing
                }
                let result;
                key = Symbol('key');// Set the function as a member value of the object (the member name is unique, preventing modification of the original object's structure value)
                context[key] = this;// Take the function to be executed as a member value of the objectresult = context[key](... params);[object.[member function](); To execute the function
                // This is the object in the function (passing the argument to the function and receiving the return value)
                delete context[key];
                return result;
            }
        Copy the code

[function]. Apply ([context],[params1,params2....]. ); 2. This is the same as call, except that ** * is passed to apply as an array of parameters. The only difference with call is that the second argument is passed as an arrayCopy the code

[function]. Bind ([context],params1,params2....) ; 2. ** has the same syntax as call, but is different from apply ** - 'call' and 'apply' both execute the current function immediately. ** Based on the idea that bind only prefixes this to [context] and stores params, but the function is not executed. **BIND's internal mechanism is to use closures (Currization of function programming). The 'function to be executed', 'changed THIS' and 'subsequent parameters to be passed to the function' are stored in the unreleased context [closure] in advance. The anonymous function will be executed directly when the execution conditions are met. In the process of executing the anonymous function, THIS and other parameters will be changed. This is the classic pre-stored idea ** 3. -bind actually works this way. Bind returns a similar anonymous function, and every time a click is executed, Javascript body.onclick = func.bind(obj,10,20,30); // If call and apply are used, they will be executed before you click on them. // If bind is not used, you can use the closure mechanism to implement this. Body.onclick = function anonymous(){// Anonymous function notifier, Favors using func.call inside anonymous functions (obj,10,20,30); } ' '4. #### use native JS to simulate a bind method' [hand tear bind] ` ```javascript // Use native JS to override the bind method to achieve the effect of bind. Bind // When the event is bound, bind a method to the event behavior // When the event behavior is triggered, the method executes, Function.prototype.bind = Function bind(context=window,... Params){// bind this is func // let _this = this; // Return function anonymous(... Inners){// this in the anonymous function returned after bind is assigned to the other content or function. // This in the anonymous function has been assigned to the person // where this is the body, // _this.call(context,... params); _this.apply(context,params.concat(inners)); Bind body. Onclick = func.bind(obj,10,20,30); Onclick = function anonymous(ev){// _this.apply(obj,10,20,30,ev); } ' '- [event object] : When the event is bound, bind a method to an event behavior to return an anonymous function to the event object. When an event is triggered and an anonymous method is executed, the browser by default passes an EV (event object) to the bound method (anonymous method), which then passes an argument to the inner anonymous function, so adding an argument to the anonymous function... Inners. So in addition to manually passing in the parameters of the anonymous function when bind executes, the parameters that the browser passes in when the event is triggered are also available to the anonymous function when it finally executesCopy the code