Polyfill for bind()

Polyfill for bind()

Introduction:

Hey👋 Readers, In this blog, you will learn

  • What is polyfill?
  • How does bind work?
  • How to write your own polyfill for bind()?

Text

🤔What is polyfill?

MDN definition: A polyfill is a piece of code (usually JavaScript on the Web) used to provide modern functionality on older browsers that do not natively support it.

Not understand? I also not understood it when I was reading it for the first time?

  • In simple terms, Some browsers don't support some built-in functions (map, filter, bind, etc...). so we have to write polyfills (actual implementation of methods) for that function so the browser can understand.

🧐How does bind work?

I hope you are aware of this keyword in javascript. if not visit it once.

  • This keyword in javascript

  • bind() is a function borrowing method that returns the copy of a function with the first argument provided to it.

Let's dive into cooooode.

1. const person = {
2.  name: "jugal",
3.  age: 21,
4. };
5.
6. function print() {
7.    console.log(`${this.name} is of ${this.age} age.`);
8. }
9.
10. const bindRef = print.bind(person);
11. bindRef();

// Output:
// jugal is of 21 age.

In the above code, what happens is,

  1. person is a normal object and print() is a method that will print the message with values of this object.

  2. At line no 8, we are calling the bind method with obj. So bind will return a new copy of the print function with setting this as a person object.

  3. So the function bindRef is a function having this as a person object, and it's just like a normal function so we can invoke it like a normal function invocation.

  4. After calling the bindRef function you will get the output "jugal is of 21 age.". So that's how bind() will create a new function copy on which it is called on by setting the this as its first argument. ( in the above example it is a print function.)

Text

😨How to write your own polyfill for bind()?

Prototype in brief:

  • Before starting polyfill for bind(), make sure you know the prototype object in javascript.

  • Let me tell you in brief, When we declare an object, array, or function in javascript, javascript assigns a prototype object to that object, array, or function.

  • Example: var arr=[1,2,3,4,5], after declaring array when we start writing arr., then it will show you the list of methods that can be applied to an array. same for array and same for functions as well.

  • Why I'm telling this is because we will use the function's prototype object to write polyfill for bind().

Polyfill for bind():

1. const person = {
2.   name: "jugal",
3.   age: 21,
4. };
5.
6. function personInfo() {
7.   console.log(`${this.name} is of ${this.age} age.`);
8. }
9.
10. const myBindRef = personInfo.myBind(person);
11. mybindRef();
  • As per the previous example, the person is the normal object, and person info is a method that consoles the person info.
  • But at line no 8, there is a function called myBind(), which is our polyfill that we have to write for actual bind().
 Function.prototype.myBind = function () {};
  • Now we want to use the myBind() on the personInfo function so that we have to add myBind() to the prototype object of the function.
  • So when we write personInfo and press ".", it will show myBind as a method to the personInfo function object.

(personInfo is a function object as functions are objects in javascript.)

 Function.prototype.myBind = function () {
        const currentObj = this;
        return function () {
               currentObj.call();
       };
 };
  • As we have discussed earlier that bind() will return the function , so as our myBind is a polyfill for bind(), we are returning the function at line no. 12.
  • We are calling a myBindRef(), which will call the personInfo method with provided person object, so we need a reference of the personInfo function in our myBind().
  • To do that, we are using the this keyword, this keyword will hold the personInfo object because we are calling myBind() on personInfo.
  • currentObj is our personInfo function on which we are calling the call() method for explicit binding.

    Learn more about call()

 Function.prototype.myBind = function (...args) {
        const currentObj = this;
        return function () {
               currentObj.call(args[0]);
       };
 };

const myBindRef = personInfo.myBind(person);
  • Here we use the rest operator to get all values that are passed as arguments to the myBind() method.
  • And we want the person object for explicit binding in the call(), so we are using args[0] to get the person object.

So till here, the basic polyfill for bind is ready

Text

This is a little advanced part of bind() polyfill, so be prepared.

First , we will pass some extra arguments to the myBind().

function personInfo(state) {
  console.log(`${this.name} is of ${this.age} age from ${state}`);
}

Function.prototype.myBind = function (...args) {
  const currentObj = this;
  const params = args.slice(1);
  return function () {
    currentObj.apply(args[0], [...params]);
  };
};

const myBindRef = personInfo.myBind(person, "gujarat");
myBindRef();
  • In params, we are extracting all other arguments except the person object by the .slice() and passing it to the personInfo using apply().
  • We use apply() because using apply() we can pass an array of arguments to the function which is restricted in call().

    Learn more about call()

Now, we will pass arguments from the function(myBindRef) which is returned from myBind()

function personInfo(state, country) {
  console.log(`${this.name} is of ${this.age} age from ${state} , ${country}`);
}

Function.prototype.myBind = function (...args) {
  const currentObj = this;
  const params = args.slice(1);
  return function (...args2) {
    currentObj.apply(args[0], [...params, ...args2]);
  };
};

const myBindRef = personInfo.myBind(person, "gujarat");
myBindRef("india");
  • Here we are passing arguments to a returned function which is myBindRef().
  • And then we are storing it in args2 array using rest operator same as above.
  • Important thing to understand here is that arguments are coming from two different sources and we have to pass them as a single array that's why we are spreading params and args2.
  • That's how we can access arguments in personInfo().

Final Output:

const person = {
  name: "jugal",
  age: 21,
};

function personInfo(state, country) {
  console.log(`${this.name} is of ${this.age} age from ${state} , ${country}`);
}

Function.prototype.myBind = function (...args) {
  const currentObj = this;
  const params = args.slice(1);
  return function (...args2) {
    currentObj.apply(args[0], [...params, ...args2]);
  };
};

const myBindRef = personInfo.myBind(person, "gujarat");
myBindRef("India");

// Output:
// jugal is of 21 age from gujarat , india

Conclusion:

  • Polyfill is a block of code that is the actual implementation of any built-in methods.
  • Some browsers don't support some methods, so we have to write polyfills for that functions.
  • bind(): bind method will return a copy of a function by setting this pointer to the very first object which we have passed in it.
  • Most asked questions in javascript interviews.

Resources:

Thanks, guys for reading my blog, I hope you understand about bind(). You can connect me on Twitter. Give feedback in the comment section on what you feel.