记前端手写方法

十二月 11, 2019

call、apply、bind 实现

call、apply、bind 本质都是改变 this 的指向,不同点 call、aplly 是直接调用函数,bind 是返回一个新的函数。call 跟 aplly 就只有参数上不同。

bind 实现

Function.prototype.myBind = function (thisArg) {
  if (typeof this !== "function") {
    throw new Error("only can bind funtion");
  }

  const args = Array.prototype.slice.call(arguments, 1);
  const _this = this;
  const nop = function () {}; // 用于箭头函数

  const bound = function () {
    return _this.apply(
      this instanceof nop ? this : thisArg,
      args.concat(Array.prototype.slice.call(arguments))
    );
  };

  if (this.prototype) {
    nop.prototype = this.prototype;
  }

  bound.prototype = new nop();

  return bound;
};

apply call 实现

Function.prototype.myCall = function (target) {
  if (typeof this !== "function") {
    throw new Error("error");
  }

  const args = Array.prototype.slice.call(arguments, 1);
  target.fn = this;

  const result = target.fn(...args);

  delete target.fn;

  return result;
};

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

  const args = arguments[1];
  target.fn = this;

  const result = target.fn(args);

  delete target.fn;

  return result;
};

const bar = function () {
  console.log(this.name, arguments);
};

bar.prototype.name = "bar";

const foo = {
  name: "foo",
};

bar.myCall(foo, 1, 2, 3); // foo [1, 2, 3]
bar.myApply(foo, [1, 2, 3]); // foo [1, 2, 3]

new 实现

我们需要知道当 new 的时候做了什么事情
创建一个新对象;
将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象)
执行构造函数中的代码(为这个新对象添加属性)
返回新对象。

function myNew(fn) {
  const args = Array.prototype.slice.call(arguments, 1);

  const o = {};
  // 实现继承,实例可以访问构造器的属性
  o.__proto__ = fn.prototype;
  const result = fn.call(o, ...args);

  return typeof result === "object" ? result : o;
}

const testNewFun = function (name) {
  this.name = name;
};

const newObj = myNew(testNewFun, "foo");

console.log(newObj); // { name: "foo" }
console.log(newObj instanceof testNewFun); // true