1, Function
call, apply and bind are used to change the context of function execution. In short, they are used to change the this point of function runtime
So under what circumstances do you need to change the direction of this? Here is an example
var name="lucy"; const obj={ name:"martin", say:function () { console.log(this.name); } }; obj.say(); //martin, this points to the obj object setTimeout(obj.say,0); //lucy, this points to the window object
As you can see from the above, the say method normally outputs martin
However, we put say in the setTimeout method. It is executed as a callback function in the timer. Therefore, when returning to the main stack, it is executed in the environment of the global execution context. At this time, this points to the window, so it outputs luck
What we actually need is that this points to the obj object. At this time, we need to change this point
setTimeout(obj.say.bind(obj),0); //martin, this points to the obj object
2, Distinction
Let's take a look at the use of apply, call and bind
apply
apply accepts two parameters. The first parameter is the direction of this, and the second parameter is the parameter accepted by the function, which is passed in the form of array
After changing this point, the original function will execute immediately, and this method only temporarily changes this point once
function fn(...args){ console.log(this,args); } let obj = { myname:"Zhang San" } fn.apply(obj,[1,2]); // this will become the passed in obj, and the passed in parameter must be an array; fn(1,2) // this points to window
When the first parameter is null and undefined, it points to window (in the browser) by default
fn.apply(null,[1,2]); // this points to window fn.apply(undefined,[1,2]); // this points to window
call
The first parameter of the call method is also the point of this, followed by a parameter list
Like apply, the original function will execute immediately after changing this point, and this method only temporarily changes this point once
function fn(...args){ console.log(this,args); } let obj = { myname:"Zhang San" } fn.call(obj,1,2); // this will become the passed in obj, and the passed in parameter must be an array; fn(1,2) // this points to window
Similarly, when the first parameter is null and undefined, it points to window (in the browser) by default
fn.call(null,[1,2]); // this points to window fn.call(undefined,[1,2]); // this points to window
bind
The bind method is very similar to the call method. The first parameter is also the direction of this. Later, a parameter list is passed in (but this parameter list can be passed in multiple times)
Changing the point of this will not be executed immediately, but will return a function that permanently changes the point of this
function fn(...args){ console.log(this,args); } let obj = { myname:"Zhang San" } const bindFn = fn.bind(obj); // this It will also become the incoming obj , bind is not executed immediately. It needs to be executed once bindFn(1,2) // this points to obj fn(1,2) // this points to window
Summary
As can be seen from the above, the differences among apply, call and bind are as follows:
-
All three can change the point of this object of the function
-
The first parameter of the three is the object to which this points. If there is no parameter or the parameter is undefined or null, it points to the global window by default
-
All three can pass parameters, but apply is an array, call is a parameter list, apply and call are one-time parameters, and bind can be passed in multiple times
-
bind is a function that returns the bound this, such as apply and call Is executed immediately
3, Realize
The steps to implement bind can be broken down into three parts:
-
Modify this point
-
Dynamic transfer parameters
// Method 1: transfer function parameters only in bind fn.bind(obj,1,2)() // Method 2: pass function parameters in bind and return functions fn.bind(obj,1)(2)
-
Compatible with new keyword
The overall implementation code is as follows:
Function.prototype.myBind = function (context) { // Judge whether the calling object is a function if (typeof this !== "function") { throw new TypeError("Error"); } // Get parameters const args = [...arguments].slice(1), fn = this; return function Fn() { // Different binding values are passed in according to the calling method return fn.apply(this instanceof Fn ? new fn(...arguments) : context, args.concat(...arguments)); } }