← all writing

Hard binding using bind method in JavaScript

The bind method allows you to create a new function with a fixed this value. This new function, when invoked, will always have the same this value, no matter how or where it's called, ensuring that the this value can never be overridden.

The bind method returns a new function that has this set to the parameter passed to bind. Use bind when you want the this value to be predictable.

Here's the syntax for the bind method:

newFunction = originalFunction.bind(thisArg, arg1, arg2, arg3);

Example 1: Hard binding with call

function displayName() {
  console.log(this.name);
}
 
var obj1 = { name: "Deepak" };
var obj2 = { name: "Chetan" };
 
var myFun = displayName;
 
var getName = function () {
  myFun.call(obj1);
};
 
getName();                      // "Deepak"
getName.call(obj2);             // "Deepak"

In the given program, the getName method consistently logs "Deepak". This is because getName is hard-bound to obj1 using the call method. Even when we explicitly call getName.call(obj2), it doesn't alter the this value within the getName method, which remains bound to obj1.

Example 2: A custom bind2 helper

function bind2(fun, obj) {
  return function () {
    fun.call(obj);
  };
}
 
function displayName() {
  console.log(this.name);
}
 
var obj1 = { name: "Deepak" };
var obj2 = { name: "Chetan" };
 
var getName = bind2(displayName, obj1);
 
getName();                      // "Deepak"
getName.call(obj2);             // "Deepak"

In this example, the getName method always has obj1 as its this value. This is because getName is hard-bound to obj1 using the bind2 function, which essentially sets the context of getName to always refer to obj1. Even if we explicitly call getName.call(obj2), it won't change the this value within the getName method.

Example 3: Adding a bind2 polyfill on Function.prototype

if (!Function.prototype.bind2) {
  Function.prototype.bind2 = function (obj) {
    var fun = this;
    return function () {
      fun.apply(obj, arguments);
    };
  };
}
 
function displayName(lastName) {
  console.log(this.name + " " + lastName);
}
 
var obj1 = { name: "Deepak" };
var obj2 = { name: "Chetan" };
 
var getName = displayName.bind2(obj1);
 
getName("Sisodiya");                           // "Deepak Sisodiya"
getName.call(obj2, "Sisodiya");                // "Deepak Sisodiya"

In this example, the getName method always has obj1 as its this value. This is because getName is hard-bound to obj1 using the bind2 function, which is now a part of the Function prototype. Even if we explicitly call getName.call(obj2), it won't change the this value.

Example 4: Using the native bind

function displayName(lastName) {
  console.log(this.name + " " + lastName);
}
 
var obj1 = { name: "Deepak" };
var obj2 = { name: "Chetan" };
 
var getName = displayName.bind(obj1);
 
getName("Sisodiya");                            // "Deepak Sisodiya"
getName.call(obj2, "Sisodiya");                 // "Deepak Sisodiya"

In this example, the getName method always has obj1 as its this value. This is because getName is hard-bound to obj1 using the native JavaScript bind function, which essentially sets the context of getName to always refer to obj1. Even if we explicitly call getName.call(obj2), it won't change the this value.

Questions

Q2's "Hello, undefined!" answer assumes a non-strict / classic script context. In strict mode (and ES modules, which are strict by default), this is undefined so this.firstName would throw TypeError instead.

1. Write the code to implement the bind method in JavaScript.

function displayName(lastName) {
  console.log(this.name + " " + lastName);
}
 
var obj1 = { name: "Deepak" };
var obj2 = { name: "Chetan" };
 
var displayName2 = displayName.myBind(obj1);
 
displayName2("Sisodiya");                            // "Deepak Sisodiya"
displayName2.call(obj2, "Sisodiya");                 // "Deepak Sisodiya"

Answer

if (!Function.prototype.myBind) {
  Function.prototype.myBind = function (obj) {
    const fun = this;
    return function () {
      fun.apply(obj, arguments);
    };
  };
}

The key detail: forward the inner function's arguments to fun using apply (which spreads the array-like arguments into individual params). Using call(obj, arguments) instead would pass the whole arguments object as a single first argument, breaking the example.

2. Rewrite the following program so that it prints the correct this.firstName.

let user = {
  firstName: "Deepak",
  sayHi() {
    alert(`Hello, ${this.firstName}!`);
  }
};
 
setTimeout(user.sayHi, 1000);

As written, this prints Hello, undefined! — when you pass user.sayHi as a callback to setTimeout, it loses its context, and this inside sayHi no longer refers to user. Instead, it refers to the global object (window in a browser). Since window doesn't have a firstName property, the template fills in undefined.

To fix this, use an arrow function or bind to explicitly set this inside the callback.

Using an arrow function:

let user = {
  firstName: "Deepak",
  sayHi() {
    alert(`Hello, ${this.firstName}!`);
  }
};
 
setTimeout(() => user.sayHi(), 1000);

Using the bind method:

let user = {
  firstName: "Deepak",
  sayHi() {
    alert(`Hello, ${this.firstName}!`);
  }
};
 
setTimeout(user.sayHi.bind(user), 1000);

Both approaches ensure that this inside sayHi refers to user, and you'll see the expected alert: Hello, Deepak!.

3. What is the output of the following program?

const obj1 = {
  name: "Piyush",
  getName: function () {
    console.log(this.name);
  },
};
 
const obj2 = {
  name: "Deepak",
};
 
const func = obj1.getName.bind(obj2);
 
func();

Answer — Deepak

Explanation: In this program, the func function is created by using the bind method on obj1.getName, with obj2 as the argument. This effectively hard-binds func to obj2. Consequently, when func is invoked, it always has the this value set to obj2. As a result, the output is "Deepak", which is the name property of obj2.