JavaScript手写系列(一)——————手写apply、call

前言

说起手写apply、call等方法是面经中常看到的问题了,其实我面试没有遇到过,但没遇到过不代表就不需要掌握。这些应该只有大厂才会考,作为一个双非毕业的普通人,还是要有一个进大厂的梦,万一哪天实现了呢,人一旦没了梦想,和咸鱼有什么区别。今天就带大家一起来实现一下简易版的call和apply。

apply

关于apply的定义,我其实没在网上找到相关的资料,找到的都是apply的用法和call的区别,我理解的就是改变执行函数中执行上下文this的指向,执行该函数。所以我们需要实现的就是其实就只有两点:
1.改变函数的this指向。
2.如果函数有参数,我们把函数参数传入。

// 改变函数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
}

接下来我们来验证一下我们手写的apply和原生的执行结果有什么不一样,这里只验证最基本的用法,高深的我不会用,更不谈实现了。

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

call实现和apply差不多,唯一需要注意的就是call接收函数参数时是一个一个传入的。

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

最后

还有最难的bind手动实现,有点难,我自己还没搞明白,就不出来献丑了,先立个flag,等我搞明白了再回来补上。

猜你喜欢

转载自blog.csdn.net/Salange1/article/details/127493047
今日推荐