手写call,apply,bind

1. 手写call函数

  1. 判断调用对象是否为函数,即使我们是定义在函数的原型上的,但是可能出现使用 call 等方式调用的情况。
  2. 判断传入上下文对象是否存在,如果不存在,则设置为 window 。
  3. 处理传入的参数,截取第一个参数后的所有参数。
  4. 将函数作为上下文对象的一个属性。
  5. 使用上下文对象来调用这个方法,并保存返回结果。
  6. 删除刚才新增的属性。
  7. 返回结果。
Function.prototype.myCall = function(context){
  //准备1:判断调用对象是否为函数
  if(typeof this !== "function"){
    console.error("type error");
  }
  // 准备2:判断 context 是否传入,如果未传入则设置为 window
  context = context ||window;
  // 准备3:获取参数
  let args = [...arguments].slice(1);

  // 1.将调用函数设为对象的方法
  context.fn = this;
  // 2.调用函数
  let result = context.fn(...args);
  // 3.将属性删除
  delete context.fn;
  return result;
}

2. 手写apply函数

  1. 判断调用对象是否为函数,即使我们是定义在函数的原型上的,但是可能出现使用 call 等方式调用的情况。
  2. 判断传入上下文对象是否存在,如果不存在,则设置为 window 。
  3. 将函数作为上下文对象的一个属性。
  4. 判断参数值是否传入
  5. 使用上下文对象来调用这个方法,并保存返回结果。
  6. 删除刚才新增的属性
  7. 返回结果
Function.prototype.myApply = function(context){
  if(typeof this !== "function"){
    throw new TypeError("Error");
  }

  context = context || window;
  let result = null;
  context.fn = this;
  if(arguments[1]){
    result = context.fn(...arguments[1]);
  }else{
    result = context.fn();
  }

  delete context.fn;
  return result;
}

3. 手写bind函数

3.1. 简陋版

  1. 在bind之前,我们已经了解了call和apply的实现,主要区别就是bind返回一个新的函数(具有原函数的功能)。
  2. 在绑定this之后,可以使用call或apply来表示那个返回的函数
Function.prototype.myBind = function(thisArg,...list){
    let fn = this; // 目标函数
    return function(...arg2){
      return fn.apply(thisArg,[...list,...arg2])
    }
}
// ---------------------------------------------------------
Function.prototype.myBind1 = function (...args) {
	var thisFunc = this, thatObj = args[0];
	args = args.slice(1);
	return function (...arg) {
		args = args.concat(arg);
		return thisFunc.call(thatObj, ...args);
	}
}

3.2. 完整版

  1. 判断调用对象是否为函数,即使我们是定义在函数的原型上的,但是可能出现使用 call 等方式调用的情况。
  2. 保存当前函数的引用,获取其余传入参数值。
  3. 创建一个函数返回
  4. 函数内部使用 apply 来绑定函数调用,需要判断函数作为构造函数的情况,这个时候需要传入当前函数的 this 给 apply 调用,其余情况都传入指定的上下文对象。

Function .prototype.myBind = function(context){
  if (typeof this !== "function") {
    throw new TypeError("Error");
  }
  let args = [...arguments].slice(1), fn = this;
  return Function Fn(){
    return fn.apply(
      this instanceof Fn ? this : context,args.concat(...arguments)
    )
  }
}

3.3. 终极版

既然返回的是一个函数,这个函数除了自调用,我们把它作为构造函数(也就是说使用new来调用)可以吗,按常理来说是可以的。原生 bind 函数也是可以实现的。

但此时的myBind函数创建的新函数并不能当做构造函数使用,为了解决此问题,我们需要将myBind函数中的prototype指向目标函数的prototype,constructor也需要指向目标函数(也就是手写一个继承)

Function.prototype.myBind = function(context) {
  // 判断调用对象是否为函数
  if (typeof this !== "function") {
    throw new TypeError("Error");
  }
  // 获取参数
  let args = [...arguments].slice(1)
  let fn = this
  
  let Fn = function Fn() {
    return fn.apply(
      this instanceof Fn ? this : context,
      args.concat(...arguments)
    )
  // 将myBind函数中的prototype指向目标函数的prototype,constructor也需要指向目标函数(也就是手写一个继承
  Fn.prototype = Object.create(fn.prototype)
  Fn.prototype.constructor = fn
  return Fn
  }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值