原型

原型总的来说就两点:

  1. 构造函数拥有 prototype 属性,它指向的对象被称为原型对象,原型对象拥有 constructor 属性,指回构造函数。构造函数的实例拥有__proto__属性,指向构造函数的 prototype;构造函数同时可以是实例对象,所以也拥有__proto__属性。这就形成了原型链。
  2. 属性查找:对象首先在本身查找相应属性,如果找不到,就会往上遍历原型链查找。

原型链

经典原型图

instanceof

function Foo() {}

Object instanceof Object; // true
Function instanceof Function; // true
Number instanceof Number; // false
String instanceof String; // false
Function instanceof Object; // true
Foo instanceof Function; // true
Foo instanceof Foo; // false

原理

one more time!

instanceof
function myInstanceof(left, right) {
  if (typeof left !== "object")
    throw newError("instanceof left-value can't be primitive");

  let proto = left.__proto__;
  let prototype = right.prototype;

  while (true) {
    if (proto === null) return false;
    else if (proto === prototype) return true;
    proto = proto.__proto__;
  }
}

继承

  1. 原型链:不能传参、共用引用类型
  2. 盗用构造函数:原理是使用 call,缺点是函数不能复用、不能访问父类原型方法
  3. 组合继承:call + new SuperType(),调用两次父构造函数
  4. 原型式继承:被规范为Object.create,不需要单独创建构造函数,缺点还是共用引用类型
  5. 寄生式继承:Object.create + 工厂模式,添加的方法无法复用
  6. 寄生式组合继承:解决两次调用父构造函数问题
function inheritPrototype(subType, superType) {
  let o = Object.create(superType.prototype); // 创建对象 o.__proto__ == superType.prototype
  o.constructor = subType; // 增强对象 superType.prototype.constructor == superType
  subType.prototype = o; // 赋值对象
}

寄生组合继承的原理

小结

原型其实就两点

  1. 实例的隐式原型指向构造函数的显式原型
  2. 属性查找会沿着原型链向上而行
  3. 继承方式和对应缺点