JavaScript handwriting series (1) ————— handwriting apply, call

foreword

Speaking of handwriting apply, call and other methods are common problems in face-to-face interviews. In fact, I have never encountered them in interviews, but if I have not encountered them, it does not mean that I do not need to master them. These should only be tested by big factories. As an ordinary person who graduated from both non-graduates, he still has a dream of entering a big factory. What if one day it comes true? Once a person loses his dream, what is the difference from a salted fish. Today, I will take everyone to realize the simple version of call and apply.

apply

Regarding applythe definition of , I actually didn’t find relevant information on the Internet. What I found was the difference applybetween usage and call. What I understand is to change the execution context this point in the execution function and execute the function . So what we need to achieve is actually only two points:
1. Change the this point of the function.
2. If the function has parameters, we pass in the function parameters.

// 改变函数this指向 我们应该从Function原型上入手
Function.prototype.myApply = (context) { // context表示函数传入的执行上下文
   if(typeof this !== 'function' ) { // 调用apply的应该是一个函数,this就是调用apply的函数
     throw new Error('type Error')
   }

   if (context === null || context === undefined) {
    context = window // 执行上下文不存在时直接指向全局window
  } else {
    context = Object(context) // 值为原始值(Number,Boolean,String),this指向其实例对象 引用类不变
  }

  const fnSymbol = Symbol()
  context[fnSymbol] = this 
  context[fn] = this // 其实这儿用fn表好理解,这儿用Symbol是为了防止调用函数的对象中有fn属性。

  const args = arguments[1] // 获取参数

  // apply的第二个参数是数组, 记住appy和array对应就行了 之前老师记不住
  const result = args.length > 1 ? context[fnSymbol](...args) : context[fnSymbol]()
  delete context[fnSymbol]
  return result
}

Next, let's verify the difference between our handwritten apply and the original execution result. Here we only verify the most basic usage. I don't know how to use advanced ones, let alone implement them.

const obj = {
  data: [1, 3, 4],
  add: function (a, b, c) {
    return a + b + c
  }
}

const add = obj.add;

const res = add.myApply(obj, obj.data)
const res1 = add.apply(obj,obj.data)
console.log(res,res1) // 8 8

call

callThe implementation is applyalmost the same, the only thing to note is that callwhen receiving function parameters, they are passed in one by one.

Function.prototype.myCall = function(context) {
  if (typeof this !== 'function'){
    console.log('type Error')
  }

  if (context === null && context === undefined){
    context = window // 若执行上下文为空直接指向全局window
  }else {
    context = Object(context) // 基础数据类型转化为实例对象
  }

  const fnSymbol = Symbol()

  context[fnSymbol] = this;

  const args = [...arguments].slice(1) // 这里使用结构获取函数传入的所有参数。

  const result = context[fnSymbol](...args)

  delete context[fnSymbol]
  return result
}


// 验证
const obj = {
  data: [1, 3, 4],
  add: function (a, b, c) {
    return a + b + c
  }
}

const add = obj.add;

const res = add.myCall(obj, ...obj.data)
const res1 = add.call(obj, ...obj.data)

console.log(res,res1) // 8 8

at last

There is also the most difficult bindmanual implementation, which is a bit difficult. I haven't figured it out myself, so I won't come out to make a fool of myself. I will set a flag first, and I will come back to make it up when I figure it out.

Guess you like

Origin blog.csdn.net/Salange1/article/details/127493047