手写call 、apply、bind

42 阅读1分钟

1. 手写call

     Function.prototype.myCall = function(context,...args){
      // 如果context是null或者undefined,默认指向全局对象(浏览器是window,Node是globalThis)
      context = context || globalThis
      const fnSymbol = symbol('fn') // 创建一个独一无二的属性名
      context[fnSymbol] = this // this指向调用myCall的函数,因为谁调用myCall,this就执行谁
      const result =  context[fnSymbol](...args)
      delete context[fnSymbol];  // 删除临时属性,避免污染传入的 context 对象
      return result
    }
   

使用示例

    function showAge(age){
      console.log(`我叫 ${this.name}, 今年 ${age} 岁。`);
    }
    showAge.myCall({name: '张三'}, 18) // 我叫 张三, 今年 18 岁。

2.手写apply

 Function.prototype.myApply = function(context,argsArray){
      context = context || globalThis
      const fnSymbol = symbol('fn') 
      context[fnSymbol] = this 
      // 判断是否有传入参数数组。如果有,则展开传递;如果没有,则直接调用
      const result =  argsArray ? context[fnSymbol](...argsArray) : context[fnSymbol]();
      delete context[fnSymbol];  
      return result
    }

使用示例

  function showInfo(age, city) {
    console.log(`我叫 ${this.name}, 今年 ${age} 岁,来自 ${city}。`);
  }
  showInfo.myApply({ name: 'Charlie' }, [30, '北京']); // 输出: 我叫 Charlie, 今年 30 岁,来自 北京。

3.手写bind

Function.prototype.myBind = function (context, ...bindArgs) {
      const self = this;
      function boundFn(...args) {
        if (this instanceof boundFn) { //这里的this指的是你new boundFn时创建的新的对象
          return new self(...bindArgs, ...args);
        }
        return self.apply(context, [...bindArgs, ...args]);//this是动态变动的,而self就是Greet
      }
      boundFn.prototype = Object.create(self.prototype);
      return boundFn;
  };

普通示例

    const person = { name: "Tom" };
    function greet(age, city) {
      console.log(`Hi, I am ${this.name}, age ${age}, from ${city}`);
    }
    const bound = greet.myBind(person, 25);
    bound("Guangzhou"); //Hi, I am Tom, age 25, from Guangzhou

new

 // 餐厅预订系统的例子
function Reservation(restaurantId, customerName, partySize, date) {
  this.restaurantId = restaurantId;
  this.customerName = customerName;
  this.partySize = partySize;
  this.date = date;
  this.status = 'pending';
}

Reservation.prototype.confirm = function() {
  this.status = 'confirmed';
  console.log(`${this.customerName}${this.partySize}人预订已确认`);
};

// 为特定餐厅创建预配置的预订构造函数
const RestaurantAReservation = Reservation.bind(null, 'restaurant-a-id');

// 使用预配置的构造函数创建预订
const booking = new RestaurantAReservation('张三', 4, new Date('2023-06-15'));
booking.confirm(); // 输出: 张三的4人预订已确认

console.log(booking instanceof Reservation); // true
console.log(booking.restaurantId); // restaurant-a-id