On call apply and bind in javascript

  • 2021-01-22 04:52:23
  • OfStack

call, apply, and bind are the three methods that come with the Function object. The main purpose of these three methods is to change the direction of the this in the function, so as to achieve the effect of 'move the window'. This paper will explain these three methods in detail, and list several classic application scenarios.

call(thisArgs [,args...])

This method can pass an thisArgs argument and an argument list. thisArgs specifies the caller of the function at run time, which is the this object in the function. The argument list is passed to the calling function. The value of thisArgs can be obtained in the following four situations:

(1) Do not pass null,undefined, this refers to window object

(2) Pass the name of another function. The this in the function refers to a reference to this function

(3) Passing basic types such as string, value or Boolean type, this in the function refers to its corresponding wrapper object, such as String, Number, Boolean

(4) Passing 1 object. this in the function points to this object


function a(){
 console.log(this); // Output function a In the this object 
}
function b(){} // Define a function b

var obj = {name:'onepixel'}; // Define the object obj

a.call(); //window
a.call(null); //window
a.call(undefined);//window
a.call(1); //Number
a.call(''); //String
a.call(true); //Boolean
a.call(b);// function b(){}
a.call(obj); //Object

This is the core function of ES38en. It allows you to call a method on an object that is not defined by that object, and the method can access properties on that object. I'll talk more about the benefits of this in a moment, but let's take a simple example:


var a = {

 name:'onepixel', // define a The properties of the 

 say:function(){ // define a The method of 
  console.log("Hi,I'm function a!");
 }
};

function b(name){
 console.log("Post params: "+ name);
 console.log("I'm "+ this.name);
 this.say();
}

b.call(a,'test');
>>
Post params: test
I'm onepixel
I'm function a!

When b.call is executed, the string 'test' is passed as an argument to the function b. Because of call, the function this in the function b points to the object a, so it is equivalent to calling the function b on the object a, which is not defined in fact.

apply(thisArgs[,args[]])

The only difference between apply and call is the way the second argument is passed. The second argument of apply must be an array, while call allows a list of arguments to be passed. Note that although ES64en receives an array of arguments, it is passed to the calling function as a list of arguments. Let's look at a simple example:


function b(x,y,z){
 console.log(x,y,z);
}

b.apply(null,[1,2,3]); // 1 2 3

This feature of apply is important and will be mentioned in the following application scenarios.

bind(thisArgs [,args...])

bind is a new method in ES5, which is similar to call, but significantly different from call/apply. In other words, calling call or apply will automatically execute the corresponding function, while bind will not execute the corresponding function, but only return a reference to the function. At first glance, bind seems to be a little behind call/apply, so why should ES5 introduce bind?

In fact, the real purpose of ES5 introducing bind is to make up for call/apply. Because call/apply automatically performs the target function, it cannot be used in the event binding function. Because the event binding function does not need to be executed manually, it is automatically executed internally by JS when the event is triggered. While ES96en implements the change function ES97en, it will not automatically execute the target function, so it can perfectly solve the above problems. See 1 example to understand:


var obj = {name:'onepixel'};

/**
 *  to document add click Event listener, and bind onClick function 
 *  through bind Methods set up onClick the this for obj , and pass the parameters p1,p2
 */
document.addEventListener('click',onClick.bind(obj,'p1','p2'),false);

// Triggered and executed when a web page is clicked 
function onClick(a,b){
 console.log(
   this.name, //onepixel
   a, //p1
   b //p2
 )
}

When clicking on the web, triggered onClick execution, output onepixel p1 p2, showed that the this onClick bind change into obj object, in order to bind in-depth understanding, we look at 1 polyfill bind under implementation:


if (!Function.prototype.bind) {
 Function.prototype.bind = function (oThis) {
  var aArgs = Array.prototype.slice.call(arguments, 1),
   fToBind = this, //this In this case, I'm referring to the target function 
   fBound = function () {
    return fToBind.apply(
     // If it is executed externally var obj = new fBound(), will obj As final this Give up use oThis
     this instanceof fToBind
       ? this // At this time this is new Out of the obj
       : oThis || this, // If the passed oThis Invalid, will be fBound As the caller of this

     // Will be sent to you by bind The passed argument is merged with the argument passed at the time of the call and passed as the final argument 
     aArgs.concat(Array.prototype.slice.call(arguments)));
   };

  // Copy the prototype object of the target function into the new function, since the target function may be used as a constructor 
  fBound.prototype = this.prototype;

  // return fBond Is invoked externally on demand 
  return fBound;
 };
}

Application Scenario 1: Inheritance

As we all know, there is no such as Java in JavaScript, C # extend keyword in a high-level language, thus JS had no concept of inheritance, if 1 set to inherit, call and apply can realize this function:


function Animal(name,weight){
 this.name = name;
 this.weight = weight;
}

function Cat(){
 Animal.call(this,'cat','50');
 //Animal.apply(this,['cat','50']);

 this.say = function(){
  console.log("I am " + this.name+",my weight is " + this.weight);
 }
}

var cat = new Cat();
cat.say();//I am cat,my weight is 50

When cat is generated by the new operator, the this in Cat refers to the cat object. The key to inheritance is that Animal is implemented in Cat.call(this,'cat','50'), and this is passed as an thisArgs parameter in call, so this in Animal method refers to this in Cat. this refers to the cat object, so this refers to the cat object. The properties of name and weight are defined in Animal, which means that the properties of name are defined in cat. Therefore, the cat object has the properties defined in Animal, thus achieving inheritance purposes.

Application Scenario 2: Grafting

Before we move on, let's first recognize a non-standard term in JavaScript: ArrayLike(Class Arrays/Pseudo Arrays)

The ArrayLike object is part of the behavior of an array, which has already been shown in DOM, and the rise of jQuery makes ArrayLike shine in JavaScript. The beauty of the ArrayLike object is that it is similar to the native Array object, but it is built freely, as it is an extension of the JavaScript object by the developer, which means that the prototype (prototype) can be defined freely without polluting the native JS object.

ArrayLike objects are widely used in JS, for example, NodeList in DOM and arguments in functions are array objects, which store each element like array 1, but it does not have methods to manipulate the array. We can use call to 'shift' some methods of the array to ArrayLike objects, so as to achieve the purpose of manipulating the elements. For example, we can traverse the function arguments like this:


function test(){
 // detection arguments Whether it is Array An instance of the 
 console.log(
   arguments instanceof Array, //false
   Array.isArray(arguments) //false
 );
 // judge arguments Is there a forEach methods 
 console.log(arguments.forEach); //undefined

 //  I'm going to take the forEach Applied to the arguments on 
 Array.prototype.forEach.call(arguments,function(item){
  console.log(item); // 1 2 3 4
 });

}
test(1,2,3,4);

In addition, apply has a unique feature that we mentioned above, which is that apply accepts an array and passes it to a calling function as an argument list. This feature makes ES195en look a bit better than ES196en, for example, in a scenario where you are given an array [1,3,4,7] and you find the largest element in the array, and you know there is no way to get the maximum element in the array, usually you have to write code to do that. As we know, the Math object has one method to get the maximum value, Math.max (), and the max method passes a list of parameters and returns the maximum value of those parameters. apply can not only apply the max method of Math object to other objects, but also convert an array into a parameter list and pass it to max.


var arr = [2,3,1,5,4];

Math.max.apply(null,arr); // 5

The above are some classic call and apply application scenarios. Master these techniques and apply these features to your actual projects, which will make your code look more interesting!


Related articles: