Handwritten call and apply together

Time:2021-4-25

1. What are call and apply

Portal:Understanding and using apply() and call() in JS
As for why handwritten code, not only for the interview, but also to help us better understand the logic of the code, the best way to go deep into the principle.

2. Handwritten call

Writing a call method is the same as writing a project. We should first analyze the functional points of their requirements, and then break them one by one.
First, we need to knowcallIs a method on the function prototype, which is used to bind objects and parameters and execute functions. The usage is as follows:

function.call(thisObj, arg1, arg2, ...)

Start to realize:

  1. We give our handwritten call method mycall, the first parameter we acceptthisObjIs the value of the target object when the target function is executed, from the second optional parameterarg1The other parameters at the beginning will be taken as the actual parameters when the objective function is executed.
  2. Need analysiscallWhat are the functions“Demand”

    • It is necessary to judge whether it is a strict mode (the direction of this scope, and the non strict mode needs special treatment for thisobj)
    • How to judge the strict mode
    • What if thisobj is not an object type, because we are hijacking bound objects

The code is as follows:

//First, apply is the prototype chain Function.prototype A method on
Function.prototype.myCall = function() {
  //Get all the parameters through arguments
  //The first parameter is the bound this object
  var thisObj = arguments[0];
  //Judge whether the mode is strict or not
  var isStrictMode = (function(){return this === undefined}())
  if (!isStrictMode) {
    //If the value of thisobj is null or undefined in non strict mode, you need to set thisobj as a global object
    if (thisObj === null || thisObj === undefined) {
      //When getting global objects, both browser environment and node environment should be considered
      thisObj = (function(){return this}())
    } else {
      //Non object type, need to convert type
      var tthisObjType = typeof thisObj
      if (thisObjType === 'number') {
       thisObj = new Number(thisObj)
      } else if (thisObjType === 'string') {
        thisObj = new String(thisObj)
      } else if (thisObjType === 'boolean') {
        thisObj = new Boolean(thisObj)
      }
    }
  }
  //Remaining parameters from index 1
  var invokeParams = [...arguments].slice(1);
  //Next, we need to call the objective function, so how to get the objective function?
  //In fact, this is the objective function, because mycall is called as a method. This of course points to the calling object, which is the objective function
  //The purpose of this assignment process is to make the semantics clearer
  var invokeFunc = this;
  //At this time, if the thisobj object is still null or undefined, it means that it is in strict mode, and the first parameter is not specified, or the value of the first parameter itself is null or undefined. At this time, the objective function is executed as an ordinary function and the result is returned
  if (thisObj === null || thisObj === undefined) {
    return invokeFunc(...invokeParams)
  }
  // otherwise, let the target function become a member method of the thisObj object, and then call it.
  //Intuitively, the object function can be assigned to the object attribute directly. In order to make the key value unique and prevent the original attribute of thisobj object from being covered, a unique attribute name can be created and handled with symbol
  var symbolPropName = Symbol(thisObj)
  thisObj[symbolPropName] = invokeFunc
  //Returns the result of the execution of the objective function
  return thisObj[symbolPropName](...invokeParams)
}

Test the code:

Math.max.myCall(null, 1,2,3,4,5)
// 5

function mycallTest(a, b) {
  var args = [].slice.myCall(arguments)
  console.log(arguments, args)
}
mycallTest(1, 2)

var obj = {
  name: 'jack'
};
var name = 'ross';
function getName() {
  return this.name;
}
getName();
getName.myCall(obj);

As you can see, there are some effects. But after all, it’s handwritten, which is different from the source code. Considering the situation, it may not be in place, and there may be bug scenarios.

3. Handwritten apply

When we write the call, it’s much more convenient to apply, and a lot of logic is basically the same. We only need to pay attention to the differences between the two methods: the second parameter is an array, so we don’t need to write comments below, just add the code directly:

Function.prototype.myApply = function(thisObj, params) {
  var isStrict = (function(){return this === undefined}())
  if (!isStrict) {
    var thisObjType = typeof thisObj
    if (thisObjType === 'number') {
     thisObj = new Number(thisObj)
    } else if (thisObjType === 'string') {
      thisObj = new String(thisObj)
    } else if (thisObjType === 'boolean') {
      thisObj = new Boolean(thisObj)
    }
  }
  var invokeFunc = this;
  //Process the second parameter
  var invokeParams = Array.isArray(params) ? params : [];
  if (thisObj === null || thisObj === undefined) {
    return invokeFunc(...invokeParams)
  }
  var symbolPropName = Symbol(thisObj)
  thisObj[symbolPropName] = invokeFunc
  return thisObj[symbolPropName](...invokeParams)
}

A simple test:

Math.max.myApply(null, [1, 2, 4, 8])
// 8

OK, it’s done!

Recommended Today

What is “hybrid cloud”?

In this paper, we define the concept of “hybrid cloud”, explain four different cloud deployment models of hybrid cloud, and deeply analyze the industrial trend of hybrid cloud through a series of data and charts. 01 introduction Hybrid cloud is a computing environment that integrates multiple platforms and data centers. Generally speaking, hybrid cloud is […]