Javascript Function Methods: Call vs Apply vs Bind

Javascript functions have these three methods: call(), apply() and bind(). They have more methods that I?m going to ignore. Don?t worry, you?ll use these three the most.

eg: someFunc.call()

The Basics: Call vs Apply

What do these methods do? Glad you asked. Look at how the following three invocations lead to identical output:

var printTwo =function () { console.log(2);};printTwo(); // 2printTwo.call(); // 2printTwo.apply(); // 2

Call and apply are very similar: both invoke the function they are called on, and take a ?this? argument as their first argument. I?ll talk about this soon.

The difference between call() and apply() is that call() passes all arguments after the first one on to the invoked function, while apply() takes an array as its second argument and passes the members of that array as arguments. The following have the same effect.

someFunc.call(thisArg, 1, 2, 3) VS someFunc.apply(thisArg, [1, 2, 3])

What?s the deal with the this argument? It is used to set the value of this inside the function you?re invoking, just as if the function were a method invoked on the object you pass as your this argument.

var someFunc = function () { return this.length}

With the above example, someFunc.apply([1, 2, 3]) would return 3 and so would someFunc.call([1, 2, 3]). This happens because each invocation is the equivalent of:

[1, 2, 3].someFunc(); //3

However, someFunc() invoked without a special binding for this would return undefined, because this is bound to the window object by default.

Default Binding of ?this?

Before we move on, understanding the binding of this in various contexts is foundational to your understanding of Javascript, and if you don?t know about it, the following video will get you started quickly (5:12 is a good place to start).

Anyway, call() and apply() can be very useful. If you?ve got an array that you want to pass as separate arguments to a some function, you can do this:

someFunc.apply(null, array);

Sidenote: there is some really cool ES6 syntax, the rest/spread operator, that allows you achieve the same result as apply by spreading out an array into a function call:

someFunc( ?array) //same result as the previous example

Remember, when using these methods the first argument gets bound to this when the function is invoked, which we haven?t fully explored yet. If you have a method on one object that you want to use on another object, the this argument becomes quite useful:

var dog = { noise: ?arf?, speak: function () { console.log(this.noise) }};var cat = { noise: ?meow?};dog.speak.call(cat); // meow

But that last line is very ugly. Instead we could do:

cat.speak = dog.speak;cat.speak(); //meow

That looks nicer (not that it?s better code) and we can use cat?s new speak() method all we want. So what?s the deal with bind() then? How is it useful?

Using the Bind Method

Let?s say we want the cat to speak in one second. Easy, we?ll use JavaScripts?s setTimeout().

setTimeout(cat.speak, 1000); // (one second elapses?) undefined

Oops! The cat didn?t meow. Why?s that? Let?s try to figure it out. It seems like we gave setTimeout the cat?s version of speak(). But what did we actually pass in? Just the speak() function. When setTimeout invokes it later, there won?t be a call-time dot to the left or any relevant object for this to refer to, so instead this will refer to something useless (to us).

Bind() can come to our rescue here. What it does is return a function that is bound to the argument you pass to it when called.

setTimeout(cat.speak.bind(cat), 1000); // (one second elapses?) meow

It fixes our problem with setTimeout because we invoke it, which passes it?s return value, a newly bound function, into setTimeout. One second later, speak() is called in the context of cat.

If we held onto the bound function for longer and kept invoking it, it would always be invoked in the context of cat, even if we stored it as a method on some other object.

Conclusion

Bind can do a lot more, and the MDN page on Function.prototype.bind() is a great place to start. In fact, MDN is often a good place to start.

So to recap, apply(), call(), and bind() all take a this argument as a context to execute a function in, but call() and apply() invoke the function immediately where bind() returns a function that we can pass around or store as needed. When invoked, the bound function will always execute in the context provided as the this argument.

Final Sidenote: ES6 is really cool. I love its fat arrow functions, which can solve the setTimeout problem above without the bind method. I highly recommend learning about ES6/ES2017.

I recently started playing around with Observable Notebooks. They?re awesome! I built an interactive demonstration of time and space complexity when calculating Fibonacci numbers.

Fast Fibonacci

Fast FibonacciWhether it’s love of math, a coding challenge, or interview preparation that brought you here, I’ve got?

beta.observablehq.com

ObservableHQ doesn?t have comments as of this writing, but come back here and tell me what you think 🙂

19

No Responses

Write a response