ES6中的继承和Mixin

Database and Ruby, Python, History


ES6终于引入了class这样的关键字,即使是语法糖,至少能够让其他编程语言的程序员不会觉得那么突兀了。习惯了Ruby的继承链,总会习惯性的问,这个类的parent是谁?方法是怎么顺着继承链查找的?

下面有一副图,是从StackOverflow上复制过来的。

img

实例b通过__proto__找到类Foo的prototype,每个类的prototype就是继承于Object.prototype,通过__proto__可以找到。通过这条链,可以找到实例的方法继承关系。在Ruby里面,就是每个实例方法的继承关系,即Child < Mixin < Person。

对于类Child来说,它的__proto__是Mixin;Mixin的__proto__是Person。这样,每个类的类方法又可以通过类的__proto__来找到。在Ruby里面,这就是SingletonClass的继承链,用来实现类方法的继承关系。

一言以蔽之,__proto__就是指方法的继承关系,无论是实例,还是类。

prototype呢?有点不一样的地方,就是这里的类多了一个prototype。类Foo的prototype是Foo.prototype,对应到Ruby里面就是 对应Foo的关系。

此外,Foo.prototype.constructor === Foo.

class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }

    say() {
        console.log('Person', this.name, this.age);
    }

    static klassMethod() {
        console.log('KlassMethod from Person');
    }
}

let p1 = new Person('Phoenix', 34);
p1.say();
console.log(p1.__proto__ === Person.prototype);
console.log(Person.prototype.__proto__ === Object.prototype);
console.log(Person.prototype.__proto__.__proto__);
console.log(Person.__proto__ === Function.prototype);
console.log(Function.prototype.__proto__ === Object.prototype);
Person.klassMethod();

class Mixin extends Person {
    constructor(name, age) {
        super(name, age);
    }

    say() {
        console.log('Mixin', this.name, this.age);
    }

    static klassMethod() {
        console.log('KlassMethod from Mixin');
    }
}

let p2 = new Mixin('Amy', 34);
p2.say(); // say() will be overrided by Mixin
Mixin.klassMethod();

class Child extends Mixin {
    constructor(name, age) {
        super(name, age);
    }

    cry() {
        console.log('Wawawa!!!')
    }
}

let p3 = new Child('Mongo', 4);
p3.say();
p3.cry();

console.log(Mixin.prototype.__proto__ === Person.prototype);
console.log(Child.prototype.__proto__ === Mixin.prototype);
console.log(Child.__proto__ === Mixin);
console.log(Mixin.__proto__ === Person);
Child.klassMethod();

Ruby里面允许Mixin,即可以在继承链上插入某个Module来实现类的扩展,无论是类方法还是实例方法。

在JavaScript里面,Mixin是通过在继承链上插入隐藏类来实现的,即一个隐藏类_Klass继承于Mixin,Mixin又继承于父类,子类再继承于_Klass来实现的。此外,JavaScript里面Module类似于Python里面的Module的概念,即一堆方法的集合。和Ruby里面的Module还是有很大的差别。