Call, Apply, and Binding in JS: The Art of Being Overly Fancy

Jason Alvarez
The Startup
Published in
7 min readNov 20, 2020

--

Find this image at pexels at https://www.pexels.com/photo/sea-nature-sunset-water-119562/

Alright, so you wanna be fancy or you saw something about Call, Apply and Bind and were wondering what that was all about. In simple terms, Call, Apply and Bind are methods that can be used on or with functions and objects that allow you to access the object's properties within the function.

Now an overview on JS objects, which is what we’ll be working with since that’s what call, apply and bind are supposed to be used on. So, a JS object is something called a data structure, which is an entry-level of fancy that basically serves to hold data in a way that is easy to read and work with. Now, to explain how call, apply and bind will interact with JS objects. It basically boils down to a way to add objects to function calls. Function calls normally have to take in parameters, but with these methods, you can use function calls without having to change your functions, you know if you’re scared to break something. Call and Apply can be assumed as to what they would do, but to be more explicit about it, the call and apply methods are applied to a function to bind an object's properties to the functions this.

Anyway, I know the first thing I look for in a technical blog is the syntax or an example, so to get that out of the way, but don’t worry about not knowing how it works yet, I’m getting there, and here’s what our end product will look like:

let me = {
name: "Jason Alvarez",
hobbies: ["Traditional Art", "Digital Art", "Game Development"],
languages: ["C++", "C#", "React", "CSS", "HTML", "Javascript"]
}
let hire = function(salary) {
return `${this.name}, you're hired with a salary of ${salary}`;
}
console.log(hire.call(me, "120k"));
// "Jason Alvarez, you're hired with a salary of 120K"
let learnedLanguage = function(...languages){
this.languages = this.languages.concat(languages);
const languagesString = languages.join(" and ");
//Places the word 'and' in between the languages
const knownLanguages = this.languages.join(" and ")
return `${this.name}, You've learned ${languagesString}, congratulations! You now know
${knownLanguages}`;
}
console.log(learnedLanguage.apply(me, ["Python", "React Native"]));
//Jason Alvarez, You've learned Python and React Native, congratulations! You now know C++
and C# and React and
// CSS and HTML and Javascript and Python and React Native
function addHobby(...newHobbies){
this.hobbies = this.hobbies.concat(newHobbies);
const hobbiesStr = this.hobbies.join(" and ");
const newHobbiesStr = newHobbies.join(" and ");
return `${this.name}'s hobbies are ${hobbiesStr}. He's recently picked up
${newHobbiesStr}.`;
}
const newHobby = addHobby.bind(me);
console.log(newHobby("Blog writing", "Studying Art History"));
//Jason Alvarez's hobbies are Traditional Art and Digital Art and Game Development and Blog
writing and
//Studying Art History. He's recently picked up Blog writing and Studying Art History.

Call() :

The call method in the example is being applied to a function, hire(), and passing it the me object and an argument of salary.

let me = {
name: "Jason Alvarez",
hobbies: ["Traditional Art", "Digital Art", "Game Development"],
languages: ["C++", "C#", "React", "CSS", "HTML", "Javascript"]
}
let hire = function(salary) {
return `${this.name}, you're hired with a salary of ${salary}`;
}
console.log(hire.call(me, "120k"));
// "Jason Alvarez, you're hired with a salary of 120K"

The object being passed in has three properties (name, age, and languages), which can be accessed with the this keyword. We can see that I’m accessing my name with this.name. As for the characters surrounding this.name, that’s simply due to string interpolation that allows me to use variables and keywords within a string. The second argument of the function call serves as the argument for the hire function, which is printed out the same way my name is, through the string interpolation. So, the call will return a string starting with my name and continuing onto saying that I’ve been hired with a salary of at least 120k (ah, you’re too kind).

Real-world applications:

You may have noticed that I am not using the original object, that’s because I can use the this keyword! One must simply reassign a property of the object through this to its desired value. Let me demonstrate by slightly changing the hire function:

let me = {
name: "Jason Alvarez",
hobbies: ["Traditional Art", "Digital Art", "Game Development"],
languages: ["C++", "C#", "React", "CSS", "HTML", "Javascript"]
}
let hire = function(salary) {
this.name = this.name+salary
return `${this.name}, you're hired with a salary of ${salary}`;
}
console.log(hire.call(me, "120k"));
// "Jason Alvarez120k, you're hired with a salary of 120K"

This will mutate my original object to have a key-value pair of name: "Jason Alvarez120k", which allows for far more flexibility in the real world, as you can make a function that changes a name that is not constricted to a single object. However, that is not a requirement for real-world applications. If you wanted, you could use a slightly altered version of this code to say “Pokemon-name, I chose you.” if you’re trying to make the next pokemon game. (Also is it just me or has pokemon become staler?) One last point on call, as well as apply, which we’ll get to in a second. You may have noticed that the call method is being performed on functions with the keyword function instead of arrow functions. That is because arrow functions do not have a this of their own, thus returning incorrect values like NaN or undefined whenever you attempt to do something with them within a function. So keep the function keyword.

Apply() :

The apply method works just like the call method with one difference, instead of taking multiple arguments in the function call, it takes an array. Here’s an example that builds off the last example :

let me = {
name: "Jason Alvarez",
hobbies: ["Traditional Art", "Digital Art", "Game Development"],
languages: ["C++", "C#", "React", "CSS", "HTML", "Javascript"]
}
let learnedLanguage = function(...languages){
this.languages = this.languages.concat(languages);
const languagesString = languages.join(" and ");
//Places the word 'and' in between the languages
const knownLanguages = this.languages.join(" and ");
return `${this.name}, You've learned ${languagesString}, congratulations! You now know
${knownLanguages}`;
}
console.log(learnedLanguage.apply(me, ["Python", "React Native"]));
//Jason Alvarez, You've learned Python and React Native, congratulations! You now know C++
and C# and React and
// CSS and HTML and Javascript and Python and React Native

In this example, we develop a new function that adds languages to my list of known languages and returns a string saying that I know such and such, having recently learned whatever was passed in as an argument.

Real-world application:

If you have an array of data that you want to add without accidentally breaking an existing method, this would be the way to go. Of course, you could use call if you passed a rest parameter. However, there are other ways to perform such a function. I would suggest making a new method within your object, as to not break any existing methods while keeping the code condensed within the object. In reality, there’s almost always another way to handle a problem and it’s up to the developer to determine what the best solution is for their circumstance.

Bind() :

Finally, as for bind, this one is far more elegant, in my opinion. Now, time for you to agree with me through an example:

let me = {
name: "Jason Alvarez",
hobbies: ["Traditional Art", "Digital Art", "Game Development"],
languages: ["C++", "C#", "React", "CSS", "HTML", "Javascript"]
}
function addHobby(...newHobbies){
this.hobbies = this.hobbies.concat(newHobbies);
const hobbiesStr = this.hobbies.join(" and ");
const newHobbiesStr = newHobbies.join(" and ");
return `${this.name}'s hobbies are ${hobbiesStr}. He's recently picked up
${newHobbiesStr}.`;
}
const newHobby = addHobby.bind(me);
console.log(newHobby("Blog writing", "Studying Art History"));
//Jason Alvarez's hobbies are Traditional Art and Digital Art and Game Development and Blog
writing and
//Studying Art History. He's recently picked up Blog writing and Studying Art History.

First things first, you’ll see that addHobby is a function declaration instead of a function expression. The reason for this is because bind returns a function and we’ll need to store it so I opted to not bother assigning it to a variable. As for bind’s syntax, it starts out with the function it wants to bind an object with. After that, bind is called and passed an object as an argument. This will create a new function object with the name of the variable we are assigning the bound function to, in this case, newHobby. When calling newHobby , we simply pass it whatever arguments we want since the function is already bound to the object.

Send off :

Some small pointers before you hop off to refresh what you’ve just read.

Call

  • takes in an object to be bound followed by single arguments(not an array)

Apply

  • takes in an object to be bound followed by an array of elements

Bind :

  • Called on an existing function
  • Takes an argument of the object you want to bind the function to
  • Returns a copy of the function called on with the object bound to it
  • Binding an object to a function allows you to call that function without passing it the object whose properties you want to use

This keyword :

  • It’s cool(don't be a square dude)
  • Allows us to access an object’s properties without a reference to a specific object
  • There’s more to the this keyword but that has to do with classes and the global reference which go way out of scope for this piece. You’ve been reading long enough already. So now you know what Bind, Call and Apply do, and hopefully, I’ll be making over 120k one day. GoodBye!

--

--

Jason Alvarez
The Startup

A full stack developer, hoping to help others on their path!