(1)子类的__proto__属性,表示构造函数的继承,总是指向父类。

    (2)子类prototype属性的__proto__属性,表示方法的继承,总是指向父类的prototype属性。

    上面代码中,子类B__proto__属性指向父类A,子类Bprototype属性的__proto__属性指向父类Aprototype属性。

    这样的结果是因为,类的继承是按照下面的模式实现的。

    1. class A {
    2. }
    3. class B {
    4. }
    5. // B 的实例继承 A 的实例
    6. Object.setPrototypeOf(B.prototype, A.prototype);
    7. Object.setPrototypeOf(B, A);

    《对象的扩展》一章给出过Object.setPrototypeOf方法的实现。

    1. Object.setPrototypeOf = function (obj, proto) {
    2. obj.__proto__ = proto;
    3. return obj;
    4. }

    这两条继承链,可以这样理解:作为一个对象,子类(B)的原型(__proto__属性)是父类(A);作为一个构造函数,子类(B)的原型对象(prototype属性)是父类的原型对象(prototype属性)的实例。

    1. B.prototype = Object.create(A.prototype);
    2. // 等同于
    3. B.prototype.__proto__ = A.prototype;

    extends关键字后面可以跟多种类型的值。

    1. }

    上面代码的A,只要是一个有prototype属性的函数,就能被B继承。由于函数都有prototype属性(除了Function.prototype函数),因此A可以是任意函数。

    下面,讨论两种情况。第一种,子类继承Object类。

    这种情况下,A其实就是构造函数Object的复制,A的实例就是的实例。

    1. class A {
    2. }
    3. A.__proto__ === Function.prototype // true
    4. A.prototype.__proto__ === Object.prototype // true

    这种情况下,A作为一个基类(即不存在任何继承),就是一个普通函数,所以直接继承Function.prototype。但是,A调用后返回一个空对象(即Object实例),所以A.prototype.__proto__指向构造函数(Object)的prototype属性。

    子类实例的__proto__属性的__proto__属性,指向父类实例的__proto__属性。也就是说,子类的原型的原型,是父类的原型。

    1. var p1 = new Point(2, 3);
    2. var p2 = new ColorPoint(2, 3, 'red');
    3. p2.__proto__ === p1.__proto__ // false

    上面代码中,ColorPoint继承了Point,导致前者原型的原型是后者的原型。

    因此,通过子类实例的__proto__.__proto__属性,可以修改父类实例的行为。

    上面代码在ColorPoint的实例p2上向Point类添加方法,结果影响到了Point的实例。