JavaScript 101 - call(), apply() & bind()
Understanding JavaScript the simple way.
"JavaScript works in mysterious ways!"
I always thought about it that way. Until recently, when I decided to explore its weird behaviour and understand why it is like that.
Today, I want to share my understanding of one such mystery.
i.e. call()
, apply()
& bind()
What do they do? How you can use them?
Let's try to answer these questions in a simple way with examples.
Before we start...
You might wanna read a little bit about Object-Oriented JavaScript. It will make much more sense after that ๐
Here is simple explanation. For detailed explanation refer these docs.
Let's have a look
Let's go over functionality of each function,
call()
Syntax
call() call(thisArg) call(thisArg, arg1) call(thisArg, arg1, ... , argN)
Parameters
- thisArg
optional
- Value to be used asthis
inside function. - arg1, ..., argN
optional
- Arguments to the function in proper order.
- thisArg
Returns
whatever function returns.
Description
call()
allows the function of one object to be assigned & called for another object.You can use it like this,
<function>.call(<object>, arguments...);
Applications
func.call()
is similar tofunc()
-// Add function function add(num1, num2) { return num1 + num2; } // Both syntaxt below are valid for invoking above func. add(10, 20) // ๐๐ผ normal way add.call(this, 10, 20) // ๐๐ผ call() way. Here this will be window obj. If you are using // strict mode, this will be undefined
Function borrowing -
const somebody = { name: 'somebody', sayHi: function() { console.log('Hi, ', this.name); }, sayHello: function() { console.log('Hello, ', this.name); } } const indrajeet = { name: 'Indra', sayNamaste: function() { console.log('Namaste, ', this.name); } } // We can borrow functions from other objects like below somebody.sayHi.call(indrajeet); // returns -> "Hi, Indra" indrajeet.sayNamaste.call(somebody); // returns -> "Namaste, somebody" // what happened here? // When we are passing the first argument as an object for reference. "this" is // replaced by the provided object, making name available in another object.
Constructor chaining -
It is a bit advance for this article but feel free to know more about it here.
apply()
- the same one!
Spoiler alert! It's the same as call
๐ (with a slight change of course)
Syntax
apply(thisArg) apply(thisArg, argsArray)
Parameters
- thisArg
required
- Value to be used asthis
inside the function. Although required, you can usenull
instead ๐ - argsArray
optional
- Array of arguments for the function.
- thisArg
Returns
whatever function returns.
Description
apply()
also allows the function of one object to be assigned & called for another object.You can use it like this,
<function>.apply(<object>, [argumentsArray]);
Applications
func.apply(null)
is also similar tofunc()
-It's pretty much the same as
call()
, except for the fact that itaccepts argument array
as the second parameter.Instead of array-like object
in case ofcall()
// Add function function greet() { return 'Hellow ๐๐ผ'; } // Both syntaxt below are valid for invoking above func. greet() // ๐๐ผ normal way greet.apply(this) // ๐๐ผ apply() way. Here this will be window obj. If you are using // strict mode, this will be undefined
Append one array to another -
passing another array directly using
push()
creates array inside array. To avoid that, you can useapply()
const array1 = ['a', 'b']; const array2 = ['c', 'd']; array1.push.apply(array1, array2); console.log(array1); // result -> ["a", "b", "c", "d"]
Function borrowing -
Just like
call()
, it can also do the function borrowing magic.Constructor chaining
It is a bit advance for this article but feel free to know more about it here.
bind()
- the different one!
At last, something that's not doing the same thing ๐
bind()
is very unique and lets you do some amazing things.
This is the most tricky bit, let's be patient till we reach examples.
Syntax
bind(thisArg) bind(thisArg, arg1) bind(thisArg, arg1, ... , argN)
Parameters
- thisArg
required
- Value to be used asthis
to target function when the function is called later. If you passnull
orundefined
instead,this
of executing scope is treated asthisArg
for the new function. - argsArray
optional
- Arguments to prepend to arguments for the new function when invoking it.
- thisArg
Returns
newly created bound function.
Description
bind()
lets you bind an unbound function to the provided object with additional and possibly hidden arguments. You can usebind()
to promote reusability. It creates a new bound function! Which usually wraps the original function object and usually abstracts away reusable bits of code.You can use it like this,
<unbound_function>.bind(<object>, arguments...);
Applications
Creating a bound function -
To put it simply, once you create a
bound function
. No matter how it is called afterwards, it will always be called with a particularthis
value.Below is a good example from Docs,
this.x = 9; // here 'this' refers to global 'window' object here in the browser const module = { x: 81, getX: function() { return this.x; } }; module.getX(); // returns -> 81 const unboundGetX = module.getX; // reference to module is lost here unboundGetX(); // returns -> 9; the function gets invoked at the global scope // Create a new function with 'this' bound to module // New programmers might confuse the // global variable 'x' with module's property 'x' const boundGetX = unboundGetX.bind(module); boundGetX(); // returns 81 // now, it will always return 81
Partially applied function -
This is an interesting one! Basically, you can create wrappers over other functions with
bind()
. Talk about reusability ๐function greet(greetings, name) { return `${greetings}, ${name}`; } const sayHi = greet.bind(null, 'Hi'); const sayNamaste = greet.bind(null, 'Namaste') const result = sayHi('Indra'); // returns -> "Hi, Indra" const result2 = sayNamaste('Somebody'); // returns -> "Namaste, Somebody" const result3 = sayNamaste('XYZ', 'Redundant'); // returns -> "Namaste, XYZ" // "Redundant" is ignored, as there is no 3rd parameter in greet func.
Explicit bind inside
setTimeout()
-This is also a pretty valid use case. You can explicitly bind
this
keyword to a class instance in order to maintain the instance. If you don't usebind()
,this
keyword inside setTimeout is set towindow
obj.Checkout this example from docs,
function LateBloomer() { this.petalCount = Math.floor(Math.random() * 12) + 1; } // Declare bloom after a delay of 1 second LateBloomer.prototype.bloom = function() { window.setTimeout(this.declare.bind(this), 1000); }; LateBloomer.prototype.declare = function() { console.log(`I am a beautiful flower with ${this.petalCount} petals!`); // If we don't use bind, this keyword will be set to window obj. // and hence, will not have access to patelCount prop of LateBloomer }; const flower = new LateBloomer(); flower.bloom(); // after 1 second, calls 'flower.declare()'
Jeez... So much for simple explanation ๐
I hope this article will help you understand at least basic use-cases for these three functions.
"I am planning to push more such content regarding the basics of JavaScript in the coming months, so let me know what you feel about that."
If something is wrong or misleading, let me know in the comments below๐๐ผ. I will update it promptly.
If you like the content, please like ๐๐ผ and share the article. As it would help me reach out to more people.