手写call apply bind 函数系列

手写call

Function.prototype.myCall = function(context, ...args) { // 解构context 与arguments
   if(typeof this !== 'function') { // this 必须是函数
     throw new TypeError(`It's must be a function`)
   }
   if(!context) context = window; // 没有context,或者传递的是 null undefined,则重置为window
   const fn = Symbol(); // 指定唯一属性,防止 delete 删除错误
   context[fn] = this; // 将 this 添加到 context的属性上
   const result = context[fn](...args); // 直接调用context 的 fn
   delete context[fn]; // 删除掉context新增的symbol属性
   return result; // 返回返回值
}

手写apply

和call类似,,只是apply的参数是数组

Function.prototype.myApply = function(context, args = []) { // 解构方式
   if(typeof this !== 'function') {
     throw new TypeError(`It's must be a function`)
   }
   if(!context) context = window;
   const fn = Symbol();
   context[fn] = this;
   const result = context[fn](...args);
   delete context[fn];
   return result;
}

call 和 apply的原理都是给那个对象加个属性,调用拿到返回值后再delete掉

手写bind

Function.prototype.myBind = function (context, ...args) {
  const fn = this;
  if(typeof fn !== 'function'){
      throw new TypeError('It must be a function');
  }
  if(!context) context = window;
  return function (...otherArgs) {
    return fn.apply(context, [...args, ...otherArgs]);
  };
};

bind 的原理是返回一个函数,这个函数最终使用的参数是创建和执行的参数的集合

拓展

关于 symbol的使用,可以参考这篇文章:理解 Es6 中的 Symbol 类型 ,每一种数据类型的出现都是为了解决特殊的问题,整理Symbol有以下应用场景:

  1. 使用Symbol来作为对象属性名(key)
  2. 使用 Symbol 定义类的私有属性/方法
  3. 模块化机制
  4. 使用Symbol来替代常量保证唯一性
  5. 注册和获取全局的Symbol

参考:https://zhuanlan.zhihu.com/p/158634772

posted @ 2021-08-06 15:35  盼星星盼太阳  阅读(28)  评论(0)    收藏  举报