【手写系列】实现call、apply、bind、new

77 阅读1分钟

Call

call():在使用一个指定的this值和若干个指定的参数值的前提下调用摸个函数或方法

例:

const foo = {
  name: 'xiaohu'
}

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

a.call(foo) // 输出: xiaohu

第一步

上述方法等于:

const foo = {
  name: 'xiaohu',
  a: function () {
    console.log(this.name)
  }
}
foo.a()

所以我们可以这样

Function.prototype.myCall = function(vm){
  vm.fn = this;
  vm.fn()
  delete vm.fn
}

// 测试一下
let foo = {
  age:'16'
}
function a(){
  console.log(this.age)
}
a.myCall(foo) //out:16

第二步

call除了可以指定this,还可以指定参数

Function.prototype.myCall = function(vm,...rest){
  vm.fn = this;
  vm.fn(...rest)
  delete vm.fn
}

// 测试一下
let foo = {
  age:'16'
}
function a(name){
  console.log(name)
  console.log(this.age)
}
a.myCall(foo,'xiaohu') //out:xiaohu 16

第三步

当this为null或者undefined时,this指向window,且函数有返回值

Function.prototype.myCall = function (vm, ...rest) {
  if (typeof vm === 'undefined' || vm === null) {
    vm = globalThis
  }
  const fnSyb = Symbol()
  vm[fnSyb] = this;
  const res = vm[fnSyb](...rest)
  delete vm[fnSyb]
  return res
}

Apply

几乎跟call一致,只不过第二个参数是传递数组

Function.prototype.myApply = function(vm,args){
  if (typeof vm === 'undefined' || vm === null) {
    vm = globalThis
  }
  const fnSyb = Symbol()
  vm[fnSyb] = this;
  const res = vm[fnSyb](...rest)
  delete vm[fnSyb]
  return res
}

Bind

需要注意的是bind可以作为构造函数使用

Function.prototype.bind = function (vm, ...arg) {
  if (typeof this !== 'function') return
  const that = this
  const res = function (...args) {
    that.myApply(this instanceof res ? this : vm, arg.concat(args))
  }
  res.prototype = this.prototype
  return res
}

New

因为new是作为js的关键字,我们这边用函数来代替实现 我们还需要判断构造函数的返回值是不是一个对象,如果是就返回,没有该返回什么返回什么

function myNew(vm, ...rest) {
  const obj = new Object();
  const Constructor = vm;
  obj.__proto__ = Constructor;
  const res = Constructor.myApply(obj, rest)
  return typeof res === 'object' ? res : obj
}