Simulation Implementation of call method

Simulation Implementation of call method

Preliminary consideration

 const person = {
   name:"Xiao Ming"
 }
 function sayName() {
   console.log(this.name)
 }

 sayName.call(person)

 //result: Xiaoming

The above code has two steps

  1. call changes the direction of this to person
  2. The sayName function executed
 //guess
 const person = {
   name:"Xiao Ming",
   sayName() {
      console.log(this.name)
   }
 }
 //At this time, the "this" cliff points to person, but to implement call, we can't add attributes to every object, but adding and deleting doesn't seem to matter

First step trial version

  1. Add fn method to person object
  2. sayName function execution
  3. Remove fn method from person
 Function.prototype.myCall = function (obj) {
   console.log(obj) // {name: 'Xiaoming'}
   console.log(this) //[Function: sayName]
 }
 //See the printing result above, do you have the answer in mind

Implement in three steps

Function.prototype.myCall = function (obj) {
  obj.fn = this
  obj.fn()
  delete obj.fn
}
sayName.myCall(person) //result: Xiaoming

Step 2 add parameter version

We know that the parameters of the call function can not only change the object this points to, but also pass in other specified parameters, such as the following:

const person = {
  name: "Xiao Ming"
}

function sayName(age, phone) {
  console.log(age)
  console.log(phone)
  console.log(this.name)
}

sayName.call(person, 12, 12345) // 12 12345 Xiaoming

But the number of parameters is not controllable, so we can write tips as follows: 1.arguments is an array like object, not a real array. 2.eval is a very special method. There are different opinions on the Internet

Function.prototype.myCall = function (obj) {
  obj.fn = this

  let _arguments = deepCopy(arguments)
  delete _arguments[0]
  let args = []
  for (let key in _arguments) {
    args.push(_arguments[key])
  }
  let  args_str= args.join()
  // Obj.fn (args ﹤ STR) is obviously not the same as passing in only one string

  eval('obj.fn(' + args_str +')'); //Processed by eval

  delete obj.fn
}

sayName.myCall(person, 12, 12345) //12 12345 Xiaoming

Are you happy to write here? We have finished 90%

Step 3 ultimate evolution optimized version

1.call(obj) what if obj is null?

let name = "lord"

function sayName() {
  console.log(this.name)
}

console.log(sayName.call(null)) //lord

2.call should return at last

function getU(age, phone) {
  return{
    age,
    phone
  }
}
console.log(getU.call(person)) //{ age: undefined, phone: undefined }

The solution is very simple. The code is as follows

Function.prototype.myCall = function (obj) {
  obj = obj || window

   ...
   ...
   ...

  const result = eval('obj.fn(' + args_str +')');

  ...

  return result
}

console.log("result",getU.myCall(person, 12, 12345)) //result { age: 12, phone: 12345 }

So far, we have finished our call

Posted by daphreeek on Sun, 29 Dec 2019 06:51:07 -0800