“This is the fourth day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”

Hello, stranger! I am spring brother 🐶, a dream is to touch fish 🐟 front-end engineer, I hope my article can help you ~

Introduction to the bind method

Before you write it by hand, you need to know what the bind method is, in MDN, and introduce it like this:

The bind() method creates a new function. When bind() is called, the new function’s this is specified by the first argument to bind, and the remaining arguments are used as arguments to the new function.

If you haven’t figured it out yet, don’t worry, here’s an example to show you how it works:

const boy = {
  age: 3.getAge: function() {
    return this.age; }}const getAge = boy.getAge
getAge()
// undefined

const boyGetAge = getAge.bind(boy)
boyGetAge()
/ / 3
Copy the code

In the example above, the getAge method, although it is boy’s getAge method, because it calls this internally, at runtime this points to the global object, namely window, so window.age is undpay. The boyGetAge method, on the other hand, will have the inner this pointing to the boy object correctly, resulting in the correct 3. Here’s the official description of this example:

The simplest use of bind() is to create a function that has the same value of this no matter how it is called. A common mistake made by new JavaScript users is to take a method out of an object and then call it again, expecting this in the method to be the original object (such as passing the method in a callback). If no special treatment is done, the original object is usually lost. Based on this function, create a binding function with the original object, which neatly solves the problem:

Next, let’s look at the second use of the bind method: partial functions.

function add(a, b) {
	return a + b
}

add(1.2)
/ / 3
// 1 + 2 = 3

const newAdd = add.bind(null.3)
newAdd(1.2)
/ / 4
// 3 + 1 = 4
Copy the code

Found no? 3 replaces 1 as the first entry, 1 goes to the second, and 2 is not called because it becomes the third. The official explanation:

Another simplest use of bind() is to make a function have default initial arguments. Just write these arguments (if any) after this as arguments to bind(). When the binding function is called, these parameters are inserted at the beginning of the argument list of the target function, followed by the parameters passed to the binding function.

Ok, so these are the two most common uses, and with that in mind, we can start writing a bind method by hand.

STEP 1 implements context binding

First, bind is a method that belongs to a method, and it returns a method without changing the original method. Therefore, it needs to be attached to the prototype chain.

Function.prototype.myBind = function() {
  const fnBound = function() {}
  return fnBound
}
Copy the code

Above, should be the basic structure of our method. Now, let’s write some code to implement context binding.

// Implement context binding
Function.prototype.myBind = function(context) {
  const fnToBind = this
  const fnBound = function() {
    return fnToBind.apply(context)
  }
  return fnBound
}
Copy the code

Next, we can do a test:

const boy = {
  x: 8.getX() {return this.x}
}
const getX = boy.getX
getX.myBind(boy)()
/ / 8
Copy the code

That’s right, the core functions are done 😍😍, now let’s implement the partial functions.

STEP 2 implements partial functions

The principle of partial functions is very simple: the array of parameters passed in bind appears at the front of the array that executes the function.

Function.prototype.myBind = function(context, ... args) {
  const fnToBind = this
  const fnBound = function(. fnArgs) {
    return fnToBind.apply(context, args.concat(fnArgs))
  }
  return fnBound
}
Copy the code

Easy, right? So let’s verify that.

function add(a, b) {
	return a + b
}
add.myBind(null.10) (1.2)
/ / 11
Copy the code

When we see the results, we know that we are done and basically have reached the expected goal.

STEP 3 Complete special cases

I won’t go into details on this, but you can refer to the code of Polyfill on MDN. In short, there are several special cases to pay attention to:

  1. Not all methods can use bind, such as the delete method and the get/set method. Throw an exception when you encounter this method.

  2. You need to keep the method prototype chain intact.

  3. Instantiation methods need to be considered.

Well, that’s the end of implementing the bind method manually. All the code has been uploaded to Github. If this article is helpful to you, please like + favorites + follow yo ~

I am spring elder brother, a dream is to touch fish front end engineer ~