Call, Apply, Bind & their Polyfills

Call, Apply, Bind & their Polyfills

What is call(), apply() & bind() ?

call(), apply() & bind() are inbuilt JavaScript methods available to all JavaScript functions. These methods are used to define the context of this keyword or to change the context of this keyword.

Suppose this keyword is pointing to an object but we want it to point to some other object, let us understand this with an example:-

const person1 = {
    name: 'Bobby'
}

const person2 = {
    name: 'Deadpool',
    getName(){
        console.log(this.name) // this keyword is pointing to person2
    }
}

person2.getName() // Deadpool

In the above example, getName() is printing Deadpool, because this keyword is pointing to the person2 object and the value of the name variable inside the person1 object is 'Deadpool'.

But how can we print 'Bobby', so to print 'Bobby', we have to change the context of this keyword from person2 to person1:-

const person1 = {
    name: 'Bobby'
}

const person2 = {
    name: 'Deadpool',
    getName(){
        console.log(this.name) // this keyword is pointing to person2
    }
}

// this keyword context changed to person1
person2.getName.call(person1) // Bobby

call()

call(thisValue, args1, args2, ...) method executes the function as soon as it is called. It accepts the this value and arguments individually.

const person1 = {
    name: 'Bobby'
}

const person2 = {
    name: 'Deadpool',
    getName(city,country){
        // this keyword is pointing to person2
        console.log(`My name is ${this.name} and I am from ${city},       ${country}`)
    }  
}

// this keyword context changed to person1
person2.getName.call(person1, 'Bhopal', 'India')
// My name is Bobby and I am from Bhopal, India

Apply()

The apply(thisValue, [args1, args2]) function is similar to the call function. The only difference between call and apply is the difference in how arguments are passed.

In apply, arguments are passed as an array.

const person1 = {
    name: 'Bobby'
}

const person2 = {
    name: 'Deadpool',
    getName(city,country){
        // this keyword is pointing to person2
        console.log(`My name is ${this.name} and I am from ${city},       ${country}`)
    }  
}

// this keyword context changed to person1
person2.getName.apply(person1, ['Bhopal', 'India'])
// My name is Bobby and I am from Bhopal, India

Bind()

The bind(thisValue, args1, args2, ...) function creates a copy of a function with a new value of the this object.

It does not execute as soon as the function is called instead it makes a copy of that function and returns us the function so that we can use it later.

const person1 = {
    name: 'Bobby'
}

const person2 = {
    name: 'Deadpool',
    getName(city,country){
        // this keyword is pointing to person2
        return(`My name is ${this.name} and I am from ${city},${country}`)
    }  
}

// this keyword context changed to person1
let fullName = person2.getName.bind(person1, 'Bhopal')
console.log(fullName('India'))
// My name is Bobby and I am from Bhopal, India

Polyfill for call()

Function.prototype.myCall = function(context={}, ...rest){
    if(typeof(this) !== "function"){
        throw new Error(this + 'is not a function')
    }
    context.fn = this
    context.fn(...rest)
}

Example:-

const person1 = {
    name: 'Bobby'
}

const person2 = {
    name: 'Deadpool',
    getName(city,country){
        // this keyword is pointing to person2
        console.log(`My name is ${this.name} and I am from ${city}, ${country}`)
    }  
}

// this keyword context changed to person1
person2.getName.myCall(person1, 'Bhopal', 'India')
// My name is Bobby and I am from Bhopal, India

Polyfill for apply()

Function.prototype.myApply = function(context={},arr){
    if(typeof(this) !== 'function'){
        throw new Error(this + 'is not a function')
    }

    context.fn = this
    context.fn(...arr)
}

Example:-

const person1 = {
    name: 'Bobby'
}

const person2 = {
    name: 'Deadpool',
    getName(city,country){
        // this keyword is pointing to person2
        console.log(`My name is ${this.name} and I am from ${city}, ${country}`)
    }  
}

// this keyword context changed to person1
person2.getName.myApply(person1, ['Bhopal', 'India'])
// My name is Bobby and I am from Bhopal, India

Pollyfill for bind()

Function.prototype.myBind = function(context={}, ...args){
    if(typeof(this) !== 'function'){
        throw new Error(this + 'is not a function')
    }
    context.fn = this
    return function(...newArgs){
        context.fn(...args, ...newArgs)
    }
}

Example:-

const person1 = {
    name: 'Bobby'
}

const person2 = {
    name: 'Deadpool',
    getName(city,country){
        // this keyword is pointing to person2
        return(`My name is ${this.name} and I am from ${city},${country}`)
    }  
}

// this keyword context changed to person1
let fullName = person2.getName.bind(person1, 'Bhopal')
console.log(fullName('India'))
// My name is Bobby and I am from Bhopal, India

Final Words

And that’s it for this blog.

I hope you’ve found this blog a good referencing resource and thank you for reading.

If this blog was helpful, please do like, comment and share. Thanks, see you in the next blog.✌️