new,bind,apply,call原理及实现

218 阅读1分钟

步骤口述参考,实现笔试参考

实现new

步骤

  • 创建空对象
  • 将构造函数原型复制到创建的对象
  • 以空对象为上下文执行构造函数
  • 如果构造函数执行返回对象则返回该对象,否则返回创建的对象

实现

function mockNew() {
  const obj = {};
  const Constructor = [].shift.call(arguments);
  obj.__proto__ = Constructor.prototype;
  // 第一个传入参数已经shift
  const res = Constructor.apply(obj, arguments); 
  return typeof res === 'object' ? res : obj;
}

实现bind

步骤

  • 判断调用bind对象是否是对象
  • 创建返回函数,判断是否是new创建
  • 将函数的原型绑定到返回函数上
  • 返回创建的函数

实现

Function.prototype.mockBind = function(context) {
  if (typeof this !== 'function') {
    return TypeError('error');
  }
  const fThis = this;
  const bindArgs = [].slice.call(arguments, 1);
  const fNop = function() {};
  const fBound = function() {
    const fnArgs = [].slice.call(arguments);
    // this instanceof fBound 说明bind返回函数通过new执行的
    return fThis.apply(this instanceof fBound ? 
        this : 
        context, bindArgs.concat(fnArgs));
  }
  if(this.prototype) {
    fNop.prototype = this.prototype;
  }
  /**
   * 断开fBound原型和this原型上方法,
   * 如果fBound.prototype = this.prototype
   * 那么fBound原型上添加方法,this的原型上也会有
   */
  fBound.prototype = new fNop(); 
  // 以上效果同:fBound.prototype.__proto__ = fNop.prototype
  return fBound;
}

实现apply

步骤

  • 获取参数作为上下文context,为空默认值window
  • 把this方法作为属性绑到上下文context
  • 以context执行挂载的this方法
  • 删除挂载属性,返回执行结果

实现

function mockApply(context) {
  const ctx = context || window;
  ctx.fn = this;
  const args = arguments[1];
  let res = undefined;
  if(args) {
    res = ctx.fn(...args);
  } else {
    res = ctx.fn()
  }
  delete ctx.fn;
  return res;
}

实现call

步骤

  • 步骤同上,只是参数不一样,获取时候方式不同

实现

function mockCall(context) {
  const ctx = context || window;
  ctx.fn = this;
  const args = [...arguments].slice(1);
  const res = ctx.fn(...args);
  delete ctx.fn;
  return res;
}