手写call、apply、bind

三者区别:

1、三者都可以显式绑定函数的this指向

2、三者第一个参数都是this要指向的对象,若该参数为undefined或null,this则默认指向全局window

3、传参不同:apply是数组、call是参数列表,而bind可以分为多次传入,实现参数的合并

4、call、apply是立即执行,bind是返回绑定this之后的函数,如果这个新的函数作为构造函数被调用,那么this不再指向传入给bind的第一个参数,而是指向新生成的对象

手写call :

Function.prototype.Call = function(context){
    //判断传入的this对象为null或者是undefined时要赋值为window或global
    if(!context){
       typeof window === 'undefined' ? global : window;
    }
    // 利用Symbol创建一个唯一的key值,防止新增加的属性与obj中的属性名重复
    let fn = Symbol();
    // this指向调用call的函数
    context[fn] = this;
     let rest = [...arguments].slice(1);//获取除了this指向对象以外的参数, 空数组slice后返回的仍然是空数组
    let result = context.fn(...rest); //隐式绑定,当前函数的this指向了context.
    delete context.fn;
    return result;
}

手写apply :

Function.prototype.Apply = function (context, rest) {
    if (!context) {
        //context为null或者是undefined时,设置默认值
        context = typeof window === 'undefined' ? global : window;
    }
    let fn = Symbol();
    context[fn] = this;
    let result;
    if(rest === undefined || rest === null) {
        //undefined 或者 是 null 不是 Iterator 对象,不能被 ...
        result = context.fn(rest);
    }else if(typeof rest === 'object') {
        result = context.fn(...rest);
    }
    delete context.fn;
    return result;
}

 手写bind:

Function.prototype.Bind = function(context) {
  if (!context || context === null) {
    context = window;
  }
  let fn = this;
  let args = [...arguments].slice(1);
  let f = Symbol();
  const result = function(...args1) {
    let res = [...args, ...args1]; //bind传递的参数和函数调用时传递的参数拼接
    if (this instanceof fn) {
      // result如果作为构造函数被调用,this指向的是new出来的对象
      // this instanceof fn,判断new出来的对象是否为fn的实例
      this[f] = fn;
      this[f](res);
      delete this[f];
    } else {
      // bind返回的函数作为普通函数被调用时
      context[f] = fn;
      context[f](res );
      delete context[f];
    }
  };
  // 如果绑定的是构造函数 那么需要继承构造函数原型属性和方法
  // 实现继承的方式: 使用Object.create
  result.prototype = Object.create(fn.prototype);
  return result;
};

扩展:手写new 

function selfNew(fn, ...args) {
  // 创建一个instance对象,该对象的原型是fn.prototype
  let instance = Object.create(fn.prototype);
  // 调用构造函数,使用apply,将this指向新生成的对象
  let res = fn.apply(instance, args);
  // 如果fn函数有返回值,并且返回值是一个对象或方法,则返回该对象,否则返回新生成的instance对象
  return typeof res === "object" || typeof res === "function" ? res : instance;
}

扩展:手写instanceof

function instanceOf(obj, fn) {
  let proto = obj.__proto__;
  if (proto) {
    //判断原型对象
    if (proto === fn.prototype) {
      return true;
    } else {
       //递归判断
      return instanceOf(proto, fn);
    }
  } else {
    return false;
  }
}

 

    

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值