手写call,apply,bind函数

call函数

Function.prototype.myCall = function(ctx) {
  if (typeof this !== "function") {
    throw new TypeError("Error");
  }
  ctx = ctx || window;
  args = [...arguments].slice(1);
  ctx.fn = this;
  let res = ctx.fn(...args);
  delete ctx.fn;
  return res;
};

实现起来很简单,需要注意的一点是存在不传参数的情况,这时this指向window。


apply函数

Function.prototype.myApply = function(context) {
  if (typeof this !== "function") {
    throw new TypeError("Error");
  }

  context = context || window;
  context.fn = this;
  let res;
  if (arguments[1]) {
    res = context.fn(...arguments[1]);
  } else {
    res = context.fn();
  }
  delete context.fn;
  return res;
};

和call非常类似,需要注意的是传入apply的第二个参数是数组,这是要区别对待的。


bind函数

Function.prototype.myBind = function(context) {
  let self = this;
  let obj = [].shift.call(arguments);
  let args = [...arguments];
  return function() {
    self.apply(obj, [...args, ...arguments]);
  };
};

bind函数返回一个this指向入参对象的函数。

第2行:将原函数保存起来

第3行:提取传入的对象

第4行:提取剩余的参数

最后返回一个函数,调用apply方法,将原函数的this指向提取的对象。需要注意的是,参数 = 之前提取的剩余参数 + 调用返回的函数接受的参数。