Call, apply and Bind in Javascript

The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.

The value of this is determined by how a function is called. If it is you who calls the function then there is usually no need to use .bind, since you have control over how to call the function, and therefore its this value.

However, often it is not you who calls the function. Functions are passed to other functions as callbacks and event handlers. They are called by other code and you have no control over how the function is called, and therefore cannot control what this will refer to.

If your function requires this to be set to a specific value and you are not the one calling the function, you need to .bind the function to a specific this value.

In other words: .bind allows you to set the value of this without calling the function now.

The bind() function creates a new bound function, which is an exotic function object (a term from ECMAScript 2015) that wraps the original function object. Calling the bound function generally results in the execution of its wrapped function.

let boundFunc = func.bind(thisArg[, arg1[, arg2[, ...argN]]])

thisArg

The value to be passed as the this parameter to the target function func when the bound function is called. The value is ignored if the bound function is constructed using the new operator. When using bind to create a function (supplied as a callback) inside a setTimeout, any primitive value passed as thisArg is converted to object. If no arguments are provided to bind, the this of the executing scope is treated as the thisArg for the new function.

global.x = 9

const obj = {
  x: 70,
  getX: function() {
    return this.x
  },
}

console.log(obj.getX()) // => 70
const retrieveX = obj.getX

console.log(retrieveX()) // => 9 Because here the function gets invoked at the global scope

// But now I will change the
const boundX = retrieveX.bind(obj)
console.log(boundX()) // => 70

Further Reading

https://stackoverflow.com/questions/41391288/why-is-javascript-bind-necessary

From w3school

In JavaScript all functions are object methods.

If a function is not a method of a JavaScript object, it is a function of the global object.

var person = {
  firstName: "John",
  lastName: "Doe",
  fullName: function() {
    return this.firstName + " " + this.lastName
  },
}
person.fullName()

In a function definition, this refers to the "owner" of the function.

In the example above, this is the person object that "owns" the fullName function.

In other words, this.firstName means the firstName property of this object.

The call() method can be used to invoke (call) a method with an owner object as an argument (parameter).

With call(), an object can use a method belonging to another object.

var person = {
  fullName: function() {
    return this.firstName + " " + this.lastName
  },
}
var person1 = {
  firstName: "John",
  lastName: "Doe",
}
var person2 = {
  firstName: "Mary",
  lastName: "Doe",
}
person.fullName.call(person1) // Will return "John Doe"

CALL() : A function with argument provided individually. If you know the number of arguments to be passed or there are no argument to pass you can use call.

APPLY() : Calls a function with argument provided as an array. You can use apply if you don't know how many arguments are going to be passed to the function.

There is a advantage of using apply over call, we don't need to change the number of argument only we can change an array that is passed.

There is not big difference in performance. But we can say call is bit faster as compare to apply because an array need to evaluate in apply method.

Both call() and apply() are methods we can use to assign the this pointer for the duration of a method invocation.

global.x = 10
/* To run this file in my vs-code or in terminal (i.e. where I am in node env),
I have to use global . where as < var x = 10 > will work in browser dev-tool

var x = 10 */

var o = { x: 15 }

function f() {
  console.log(this.x)
}

f() // => 10

f.call(o) // => 15

Very Importantly note, the call() method as above will NOT work in arrow function. And this.x will produce undefined. Because, Unlike regular functions, arrow functions do not have their own 'this'

global.x = 10

const obj = {
  x: 15,
  func: () => console.log(this.x),
  func2: function() {
    console.log(this.x)
  },
}

const func = () => console.log(this.x)

func() // => undefined
func.call(obj) // => undefined
obj.func.call(obj) // => undefined
// But the following will work as expected
obj.func2.call(obj) // => 15, accessing the

The first invocation of f() will display the value of 10, because this references the global object. The second invocation (via the call method) however, will display the value 15. 15 is the value of the x property inside object obj.

The call() method invokes the function and uses its first parameter as the this pointer inside the body of the function. In other words - we've told the runtime what object to reference as 'this' while executing inside of function f().

The apply() method is identical to call(), except apply() requires an array as the second parameter. The array represents the arguments for the target method.

A> https://stackoverflow.com/questions/1986896/what-is-the-difference-between-call-and-apply?rq=1 – This page has a long answer explaining apply() with example and how correctly assigning value to “this” is so very important when defining method.

When calling a function of the form foo.bar.baz(), the object foo.bar is referred to as the receiver. When the function is called, it is the receiver that is used as the value for this. If there is no explicit receiver when a function is called, then the global object becomes the receiver.

Because functions are first-class objects in JavaScript, they can have their own methods. All functions have the methods call() and apply() which make it possible to redefine the receiver (i.e., the object that this refers to) when calling the function.

The value of this can never be null or undefined when a function is called. When null or undefined is supplied as the receiver to call() or apply(), the global object is used as the value for receiver instead.

B> The apply function is used to call another function, with a given context and arguments, provided as an array. The min and max functions can take an arbitrary number of input arguments: Math.max(val1, val2, ..., valN)

So if we call:

Math.min.apply(Math, [1,2,3,4]);

The apply function will execute:

Math.min(1,2,3,4);

Note that the first parameter, the context, is not important for these functions since they are static, they will work regardless of what is passed as the context.

Special note - With ES6, the equivalent code for the above is Math.max(...Arr)

Replacing “Math” with “null” would output same output

What is the difference between call, apply, and bind ?

At a very high level, call and apply execute a function immediately. Bind returns a new function.

Call and apply are very similar in that they allow you to invoke a function. The difference is that call takes arguments one by one, apply takes in arguments as an array.

Remember A for apply, A for array. Consider the following examples.

var john = {
  favoriteFood: 'pizza'
}

var bob = {
  favoriteFood: 'spaghetti'
}

var favFood = function(eatAction, afterEatAction) {
  console.log('It\'s time to ' + eatAction + ' ' + this.favoriteFood + '! Then ' + afterEatAction + '.')
}

bob.favFood('scarf down', 'sleep')

// bob.favFood is not a function...
// Results in error, favFood is not a method on bob
// In order to user this method for bob, I need to use call or apply

favFood.call(bob, 'scarf down', 'sleep') //It's time to scarf down spaghetti! Then sleep.

favFood.apply(john, ['scarf down', 'sleep']) //It's time to scarf down pizza! Then sleep.

favFood.call(john, ['scarf down', 'sleep']) //It's time to scarf down,sleep pizza! Then undefined.

// Notice this is not what we want, but doesn't hard error out.

// On the other hand, if I invoke apply() without passing the arguments as an array

favFood.apply(bob, 'scarf down', 'sleep') //Uncaught TypeError... hard error

Bind is used to return a function that can be invoked at a later time. The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.

var eatThenSomething = favFood.bind(bob)
eatThenSomething('gobble', 'nap') //It's time to gobble spaghetti! Then nap.

Next example of bind()

const obj  = {
    x: 42,
    getX: function() {
        return this.x;
    }
}

const unBoundX = obj.getX
console.log(unBoundX()); // => undefined

// But to get it to work
const boundX = unBoundX.bind(obj)
console.log(boundX()); // => 42

Comments