Handwritten call(), apply(), bind() methods

Table of Contents

Knowledge reserve:

1: Handwritten call method

1. Ideas

2. Realize

3. Symbol tuning

2: Handwritten apply method

1. Ideas

2. Realize

Three: Handwritten bind method

1. Ideas

2. Realize

Four: Summary

Knowledge Reserve:

All methods can call our handwritten methods, so they need to be mounted on the prototype, so we use the following code to mount

Function.prototype.myCall = function () { console.log(‘Method execution’) }

One: Handwritten call method

The call method is a common method to change the point of this. Its writing method is func.call(thisArg,att1,att2,…). The first parameter here is the instance we want to change this to. Starting from the second attribute, it is the parameter we want to pass. Because it is passed directly, we are not sure how many parameters there are here, so we need to use …args to receive when rewriting. At the same time, …args is needed for structure when using this parameter. Let’s sort out the ideas and implementation below.

1. Ideas

  • Define myCall method
  • Set this and call the original function
  • Receive the remaining parameters and return the result

2. Realization

 <script>
        // 1. Define myCall method
        Function.prototype.myCall = function (thisArg,...args) {
            // 2. Set this as the original function
            // thisArg is the object passed in and set to this
            // This here is the original function because it is the original function.myCall()
            thisArg.f = this
            // 3. Accept the remaining parameters and return the result
            const res = thisArg.f(...args)
            // Because the f attribute was added, it needs to be deleted.
            delete thisArg.f
            return res
        }
        
        //------------- Test code-------------
        const person = {
            name: 'Zhang San'
        }
        function func(numA,numB){
            console.log(this);
            console.log(numA,numB);
            return numA + numB
        }
        const res = func.myCall(person, 1, 2)
        console.log('The returned value is: ' + res);
    </script>

3. Symbol tuning

In the above code, we can see that thisArg.f is used to point to this. But this has a drawback, that is, you cannot determine whether the f method exists in thisArg, so we use Symbol for tuning. Replace the code in myCall() with the following:

 //Symbol tuning
            // 2. Set this as the original function
            // thisArg is the object passed in and set to this
            // This here is the original function because it is the original function.myCall()
            // 4. Symbol tuning
            const key = Symbol('key')
            //Here is the dynamic parsing key
            thisArg[key] = this
            // 3. Accept the remaining parameters and return the result
            const res = thisArg[key](...args)
            // Because the f attribute was added, it needs to be deleted.
            delete thisArg[key]
            return res

There is no additional running diagram here, the final effect is the same! It is more safe and reliable, and it is recommended to use this method.

Two: Handwritten apply method

The apply method is another common method of changing the point of this. This method, like the call method, changes the point of this when called. However, the difference between apply and call is that the first parameter received by apply is thisArg. (the object that needs to be pointed to), and the second parameter is an array. apply only has these two parameters, which is different from the call method. The rest is basically the same. The following is the implementation idea and specific code.

1. Ideas

  • Define myApply method
  • Set this and call the original function
  • Receive parameters and return results

2. Realization

This implementation method is actually very similar to the implementation method of myCall. The difference is that when receiving parameters, because an array has been passed, we do not need to use … to receive an uncertain number of parameters, just use args directly.

 <script>
        // 1. Define myCall method
        Function.prototype.myApply = function (thisArg,args) {
            // 2. Set this as the original function and directly use Symbol for tuning
            // thisArg is the object passed in and set to this
            // This here is the original function because it is the original function.myCall()
            // 4. Symbol tuning
            const key = Symbol('key')
            //Here is the dynamic parsing key
            thisArg[key] = this
            // 3. Accept the remaining parameters and return the result
            const res = thisArg[key](...args)
            // Because the f attribute was added, it needs to be deleted.
            delete thisArg[key]
            return res
        }

        //------------- Test code-------------
        const person = {
            name: 'Zhang San'
        }
        function func(numA,numB){
            console.log(this);
            console.log(numA,numB);
            return numA + numB
        }
        const res = func.myApply(person, [1, 2])
        console.log('The returned value is: ' + res);
    </script>

Three: Handwritten bind method

The bind method is directly different from the call method and the apply method. This method changes the specification of this when it is created. At the same time, it returns a new method. When calling the new method, you can also pass parameters. This will be the same as before. The parameters of the method are concatenated and merged. This method will not change the this point of the original method. The specific ideas and implementation are as follows.

1. Ideas

  • Define myBind method
  • Returns a new function bound to this
  • Merge bindings and newly passed parameters

2. Implementation

 <script>
        // 1. Define myBind method
        Function.prototype.myBind = function (thisArg,...args) {
            // 2. Return a new function bound to this
            return (...reArgs) => {
                // this: original function (original function.myBind)
                //3. Merge binding and newly passed in parameters, pay attention to the order.
                return this.call(thisArg,...args,...reArgs)
            }
        }

        //------------- Test code-------------
        const person = {
            name: 'Zhang San'
        }
        function func(numA,numB,numC,numD){
            console.log(this);
            console.log(numA,numB,numC,numD);
            return numA + numB + numC + numD
        }
        const bindFunc = func.myBind(person, 1, 2)
        const res = bindFunc(3,4)
        console.log('The returned value is: ' + res);
    </script>

Four: Summary

The three methods call, apply, and bind are important methods to change the point of this. Proficient use and mastery of their source code implementation principles can help us better understand and use these three methods. At the same time, it allows us to avoid many unnecessary mistakes during the project development process and improve our logical thinking ability.

Therefore, it is necessary to learn these three methods. I hope this article can be helpful to all of you~