The introduction

This, call and apply, as well as bind.

Ⅰ this

— What is this

The function’s this keyword behaves slightly differently in JavaScript than in other languages. In most cases, how the function is called determines the value of this (runtime binding).

This differs from the behavior of other languages in that the reference to this cannot be bound at creation time; its reference is bound at invocation. Alternatively, the value of this can be set through the bind function, regardless of the call.

— The call location of this

  • In the global environment

    In the global execution environment (outside any function body) this refers to the global object, and in the browser the Window object is the global object.

    console.log(this); // Window object this.sayHi = "Hello World"; console.log(sayHi); //"Hello World" console.log(window.sayHi); //"Hello World"Copy the code
  • In the function

    Inside functions, without strict mode enabled, this refers to global objects.

    function a(){ console.log(this); //window object} a();Copy the code

    If strict mode is enabled, the value of this is undefined.

    function a(){
        "use strict"
        console.log(this);              //undefined
    }
    a();
    Copy the code
  • In the class

    In a class, this is just a regular object. When the class is instantiated, the this in the class constructor refers to the object generated by the instantiation. In class methods, this refers to the class itself.

    class Person{
        constructor(){
            this.age = 21;
        };
        getThis(){
            console.log(this);
        }
    }
    let p = new Person();
    console.log(p.age);                 //21
    p.getThis();                        //Person
    Copy the code
  • In the arrow function

    In the arrow function, this still points to the global object

    Let fun = ()=>{console.log(this)} //window object fun();Copy the code
  • Object

    In the method of an object, this refers to the object on which the method was called

    var name = "mt" var obj = { name:"MT", getName(){ console.log(this.name); } } obj.getName(); Var getName = obj.getname; getName(); // Since this is a global call, the result is "mt"Copy the code

Ⅱ apply and call

Both the call and apply methods call the function with the specified this value, which sets the value of the this object inside the function when the function is called.

– apply method

Description:

The apply() method calls a function with a given this value and arguments supplied as an array.

This method takes two arguments: the value of this within the function and an array of arguments. The second argument can be an instance of Array, but it can also be the argument object passed in the function.

function sum(num1,num2){ return num1 + num2; } function callSum1(num1,num2){ return sum.apply(this,[num1,num2]); } function callSum2(num1,num2){ return sum.apply(this,arguments); } callSum1(); //20 callSum2(); / / 20Copy the code

Function:

  • Adds items from one array to another

    var array = ['a','b']; Var elements = [0]; arry.push.apply(array,elements); console.log(array);Copy the code

    If we use the push method directly, it adds the array as a single element, rather than every element in the array, so we end up with an array within an array. That’s why apply comes in handy.

  • Use Apply and the built-in functions

    var numbers = [5, 6, 2, 3, 7]; var max = Math.max.apply(null, numbers); var min = Math.min.apply(null, numbers); Max = -infinity, min = +Infinity; for (var i = 0; i < numbers.length; i++) { if (numbers[i] > max) max = numbers[i]; if (numbers[i] < min) min = numbers[i]; }Copy the code

    For requirements that require writing loops to iterate over items in a set, we can use Apply to avoid loops. This is very efficient in comparison to the normal looping method, but it runs the risk of exceeding the upper limit of the length of the JS engine parameters. If an engine has a method parameter upper limit of 4, the parameters that are actually passed to apply after the above code is executed are 5,6,2,3, rather than the full array.

    If your array of parameters is likely to be very large, the following mixed strategy is recommended, where the array is sliced and looping through the target method

    function minOfArray(arr) {
      var min = Infinity;
      var QUANTUM = 32768;
    
      for (var i = 0, len = arr.length; i < len; i += QUANTUM) {
        var submin = Math.min.apply(null, arr.slice(i, Math.min(i + QUANTUM, len)));
        min = Math.min(submin, min);
      }
    
      return min;
    }
    
    var min = minOfArray([5, 6, 2, 3, 7]);
    Copy the code

– call method

Description:

The call() method calls a function with a specified this value and one or more arguments given separately.

This method receives the same first parameter as apply, the value of this within the function, while the remaining parameters to be passed to the called function need to be listed one by one.

function sum(num1,num2){ return num1 + num2; } function callSum(num1,num2){ sum.call(this,num1,num2); } the console. The log (callSum (10, 10)); / / 20Copy the code

Function:

  • Change the this value in the function body

    window.color = "red";
    let o = {
        color:"blue"
    }
    function sayColor(){
        console.log(this.color);
    }
    sayColor.call(this);				//"red"
    sayColor.call(window);				//"red"
    sayColor.call(o);					//"blue"
    Copy the code

    In this example, you can see that the sayColor function uses the call method to change the this reference, which returns a different result. The window call to sayColor prints “red”, and the o call to sayColor prints “blue”. Since this points to window in the global scope, it also prints “red”.

  • Call the constructor for inheritance

    function Product(name, price) {
      this.name = name;
      this.price = price;
    }
    function Food(name, price) {
      Product.call(this, name, price);
      this.category = 'food';
    }
    function Toy(name, price) {
      Product.call(this, name, price);
      this.category = 'toy';
    }
    var cheese = new Food('feta', 5);
    var fun = new Toy('robot', 40);
    Copy the code

    This example declares a Product constructor, from which two child constructors are derived. In this process, in addition to having its own category attribute, each child constructor inherits two attributes from the Product parent constructor — name, price — via the call method

  • Traverse the NodeList

    <body>
        <div></div>
        <div></div>
        <div></div>
        <script>
        	let nodelist = document.querySelectorAll("div");
            [].forEach.call(nodelist,(item,index){
            	item.innerHTML = index + "Hello World"                
    		})
        </script>
    </body>
    Copy the code

    Using document. QuerySelectorAll return is not an array, but a NodeList, so if you want to use an array of forEach, call method will play a role

Ⅲ bind

Description:

The bind() method creates a new function, and when bind() is called, this of the new function is specified as the first argument to bind(), and the remaining arguments will be used as arguments to the new function.

The bind method is exactly the same as the call method, with the difference between executing immediately and waiting for execution.

window.color = "red";
var o = {
    color:"blue"
}
function sayColor(){
    console.log(this.color);
}
let a = sayColor.bind(this);
let b = sayColor.bind(window);
let c = sayColor.bind(o);
a();									//"red"
B();									//"red"
C();									//"blue"
Copy the code

As shown in the example above, when you change the this pointer in the sayColor function using bind, instead of calling it directly, you return a copy of the original function with the specified this and arguments.

Function:

  • Creating a binding function

    this.x = 9;
    var module = {
      x: 81,
      getX: function() { return this.x; }
    };
    module.getX(); 						// 81
    var retrieveX = module.getX;
    retrieveX();						//9
    var boundGetX = retrieveX.bind(module);
    boundGetX(); 						// 81
    Copy the code

    In this example, the variable X is declared in the global and module object respectively, and when we call the variable retrieveX after taking the getX method out of the Module and assigning it to the global variable, this will refer to the global again. At this point we bind the Retrieve method with the original object module through bind and we can refer this back to the original object.

  • Cooperate with setTimeout

    function LateBloomer() { this.petalCount = Math.ceil(Math.random() * 12) + 1; } LateBloomer.prototype.declare = function() { console.log('I am a beautiful flower with ' + this.petalCount + ' petals! '); }; LateBloomer.prototype.bloom = function() { window.setTimeout(this.declare.bind(this), 1000); }; var flower = new LateBloomer(); flower.bloom();Copy the code

    By default, window.settimeout () will refer to this as a global object. If the method called by setTimeout did not use bind to change this, this will refer to window. The member property petalCount cannot be printed.

    conclusion

    That’s all for this article, and the next one will review stereotypes and inheritance in JavaScript