The basic use

The core functions of call, Apply, and bind are to change the reference to this, but there are some differences between them.

call

Change this to point to and execute the function. The additional arguments are passed in as an argument list


let context = {
    name:'The mysterious Lord'
}

const myFn = function(age,height){
    console.log(this.name+':'+age+':'+height)
}

myFn.call(context,25.'180cm')  // Mysterious treasure: 25 years old: 180cm

Copy the code

apply

Much like call, change the point to this and execute the function, passing in additional arguments as an array


let context = {
    name:'The mysterious Lord'
}

const myFn = function(age,height){
    console.log(this.name+':'+age+':'+height)
}

myFn.call(context,[25.'180cm'])  // Mysterious treasure: 25 years old: 180cm

Copy the code

bind

Change this to refer to a function, and instead return a function with this changed, passed in as an argument list


let context = {
    name:'The mysterious Lord'
}

const myFn = function(age,height){
    console.log(this.name+':'+age+':'+height)
}

let myFn2  = myFn.bind(context)

myFn2(25.'180cm') // Mysterious treasure: 25 years old: 180cm

Copy the code

Manually implement call, apply, bind

To implement call and apply, we need to do two things. The first thing is to get the bound function, the second thing is to append the bound function to the object that has been replaced by hijack, and then call the appended function. Since this pointing mechanism of JS points to the caller, it seems easy to implement these two steps

Let’s take call as an example:


// Context is the object passed in to replace this
Function.prototype.myCall = function(context,... params){
    // Assign null when the replacement variable passed in is not an object
    if(typeof context === "object"){
        context = context || window
    }else{
        context = null
    }
    
    let funcName = Symbol(a)// Use the Symbol type to define temporary method names, so that methods on context do not have the same name as temporary methods
    context[funcName] = this // Get the function calledcontext[funcName](... params)delete context[funcName]  //originFunction is only a temporary property. Delete it after the call is complete
}

let context = {
    name:'The mysterious Lord'
}

const myFn = function(age,height){
    console.log(this.name+':'+age+':'+height)
}

myFn.myCall(context,25.'180cm')  // Mysterious treasure: 25 years old: 180cm


Copy the code

After the call is implemented, apply is basically implemented, but the pass-parameter mode is different:


// Context is the object passed in to replace this
Function.prototype.myApply = function(context,params){
    // Assign null when the replacement variable passed in is not an object
    if(typeof context === "object"){
        context = context || window
    }else{
        context = null
    }
    
    let funcName = Symbol(a)// Use the Symbol type to define temporary method names, so that methods on context do not have the same name as temporary methods
    context[funcName] = this // Get the function calledcontext[funcName](... params)delete context[funcName]  //originFunction is only a temporary property. Delete it after the call is complete
}

let context = {
    name:'The mysterious Lord'
}

const myFn = function(age,height){
    console.log(this.name+':'+age+':'+height)
}

myFn.myApply(context,[25.'180cm'])  // Mysterious treasure: 25 years old: 180cm


Copy the code

The bind implementation is different from the previous two, but it is simpler because bind does not call functions, so we return a function and execute myCall internally


Function.prototype.myBind = function(context){
    return (. params) = >{
        this.myCall(context,... params) } }let context = {
    name:'The mysterious Lord'
}

const myFn = function(age,height){
    console.log(this.name+':'+age+':'+height)
}

const myFn2 = myFn.myBind(context)  

myFn2(25.'180cm')   // Mysterious treasure: 25 years old: 180cm


Copy the code