【JS】手写call、apply、bind

call

首先需要了解不同传入参数的返回

  • 如果传入原始类型,this则是包装类型的对象,如传入 number 则 this 为 包装类型Number对象。
    在这里插入图片描述
  • 如果传入 nullundefined,this 为全局对象。
    在这里插入图片描述

开始封装,如果传入 nullundefined,this 为全局对象;如果传入原始类型,则通过 Object() 包装为对象。

Object.prototype.myCall = function(ctx,...args){
    
    
  ctx = ctx === null || ctx === undefined ? globalThis : Object(ctx)
}

继续完善,使用 Symbol 确保 key 的唯一性

Function.prototype.myCall = function (ctx, ...args) {
    
    
  ctx = ctx === null || ctx === undefined ? globalThis : Object(ctx)
  const key = Symbol()
  ctx[key] = this
  const r = ctx[key](...args)
}

但此时对象中会多出属性 Symbol

在这里插入图片描述

将其变为不可枚举属性,且运行完成后删除该属性即可

Function.prototype.myCall = function (ctx, ...args) {
    
    
  ctx = ctx === null || ctx === undefined ? globalThis : Object(ctx)
  const key = Symbol()
  Object.defineProperty(ctx, key, {
    
    
    value: this,
    enumerable: false,
  })
  const r = ctx[key](...args)
  delete ctx[key]
  return r
}

apply

基本同 call,区别在于需要将参数作为数组传入

Function.prototype.myApply = function (ctx, argsArray) {
    
    
  ctx = ctx === null || ctx === undefined ? globalThis : Object(ctx);
  const key = Symbol();
  Object.defineProperty(ctx, key, {
    
     value: this, enumerable: false })
  const r = argsArray ? ctx[key](...argsArray) : ctx[key]();
  delete ctx[key];
  return r;
}

bind

基本内容如下:

Function.prototype.myBind = function (context, ...args1) {
    
    
  const self = this
  return function (...args2) {
    
    
    return self.apply(context, [...args1, ...args2])
  }
}

需要考虑构造函数情况

在这里插入图片描述

但是目前的实现无法处理构造函数

在这里插入图片描述

继续优化,使用 new.target 判断是否通过 new 调用

Function.prototype.myBind = function (context, ...args1) {
    
    
  const self = this
  return function (...args2) {
    
    
    const allArgs = [...args1, ...args2]
    if (new.target) {
    
    
      return new self(...allArgs)
    } else {
    
    
      return self.apply(context, allArgs)
    }
  }
}

猜你喜欢

转载自blog.csdn.net/owo_ovo/article/details/143115569