Unraveling the Enigma of Function Invocation: A Magical Journey Beyond the Ordinary in the Realm of JavaScript

Bekhzod Ismoiliy
4 min readMay 14, 2023

--

JavaScript is an incredibly flexible language that offers numerous ways to manipulate function context. Three of these methods are bind, call, and apply. They can seem intimidating at first, but once you understand their function and use, you'll find them to be powerful tools in your coding arsenal. This article delves into what these methods do, how to use them, and how you can create custom versions. We'll also provide a few tasks to help consolidate your understanding.

Decoding the Mystery of Function Calls: Embark on a Magical Odyssey Beyond the Conventional in the Universe of JavaScript

Bind, Call, and Apply: What are they?

Every function in JavaScript has three methods: bind, call, and apply. These methods allow you to set the this value in the function, which determines the context the function runs in.

  • bind: Returns a new function, allowing you to pass in a this array and any number of arguments. The this argument is used as the context in the function.
  • call: Calls a function with a given this value and arguments provided individually.
  • apply: Similar to call, but accepts an array of arguments instead of individual ones.

Bind in action

bind creates a new function with a specified this value, allowing you to control the context in which a function is executed.

let obj = {
name: 'John',
};
function greet() {
console.log(`Hello, my name is ${this.name}`);
}
let boundGreet = greet.bind(obj);
boundGreet(); // "Hello, my name is John"

In this case, boundGreet is a new function with the same body as greet, but this is always bound to obj.

Call and Apply in action

The call and apply methods are similar to bind, but with one crucial difference: instead of creating a new function, they immediately invoke the function with the specified this value.

let obj = {
name: 'John',
};

function greet(greeting, punctuation) {
console.log(`${greeting}, my name is ${this.name}${punctuation}`);
}
greet.call(obj, 'Hello', '!'); // "Hello, my name is John!"
greet.apply(obj, ['Hello', '!']); // "Hello, my name is John!"

In both call and apply, this is set to obj. The difference is in how additional arguments are passed: call takes a list of arguments, while apply takes a single array of arguments.

Crafting Your Own Bind, Call, and Apply

You can also create your own versions of bind, call, and apply using JavaScript's prototypal nature.

You’re right, my apologies. If you want to avoid the use of .apply, .call, or .bind in your custom implementation, things get a bit more tricky. Here's how you could do it:

Function.prototype.myBind = function(context) {
var func = this;
return function(...args) {
var contextClone = Object.create(context);
contextClone.func = func;
return contextClone.func(...args);
};
};
Function.prototype.myCall = function(context, ...args) {
var contextClone = Object.create(context);
contextClone.func = this;
return contextClone.func(...args);
};
Function.prototype.myApply = function(context, args) {
var contextClone = Object.create(context);
contextClone.func = this;
return contextClone.func(...args);
};

Each of these methods works by manipulating the function’s context and then invoking the function with the specified arguments.

Let’s put the above functions to test:

const name = 'Tom';

const obj = {
name: 'Jerry',
};
function greet(greeting, punctuation) {
console.log(`${greeting}, ${this.name}${punctuation}`);
}
const boundGreet = greet.myBind(obj);

boundGreet('Hello', '!'); // Should log: "Hello, Jerry!"
greet.myCall(obj, 'Hi', '.'); // Should log: "Hi, Jerry."
greet.myApply(obj, ['Hey', '!']); // Should log: "Hey, Jerry!"

Tasks to Solidify Your Understanding

Task 1: Changing Context with Bind
Create a person object with a name and introduce method. Then, create another person2 object with just a name. Use bindto create a new function where person2 can introduce itself using the introduce method from person1.

let person1 = {
name: 'John',
introduce: function() {
console.log(`Hello, my name is ${this.name}`);
}
};
let person2 = {
name: 'Jane'
};
let introduceJane = person1.introduce.bind(person2);
introduceJane(); // "Hello, my name is Jane"

Task 2: Invoking Functions with Call and Apply
Suppose you have a car object with a describe method. Create a car2 object with the same properties but without the describe method. Use call and apply to invoke the describe method from car1 for car2.

let car1 = {
make: 'Toyota',
model: 'Camry',
describe: function() {
console.log(`This car is a ${this.make} ${this.model}`);
}
};
let car2 = {
make: 'Honda',
model: 'Civic'
};
car1.describe.call(car2); // "This car is a Honda Civic"
car1.describe.apply(car2); // "This car is a Honda Civic"

Task 3: Implementing Your Own Bind, Call, and Apply
Using the custom myBind, myCall, and myApply functions defined above, replicate the actions in Task 1 and Task 2. Confirm that they work as expected.

Understanding bind, call, and apply is key to mastering JavaScript, as they give you greater control over the context in which your functions execute. They can make your code cleaner and more flexible, and they also open up new coding patterns and paradigms. So take the time to understand and practice using them, and you'll be a more skilled JavaScript developer in no time.

--

--

Bekhzod Ismoiliy
Bekhzod Ismoiliy

Written by Bekhzod Ismoiliy

I am a highly skilled and dedicated Frontend Web Developer with a passion for creating exceptional user experiences.

No responses yet