ES6终于引入了class
这样的关键字,即使是语法糖,至少能够让其他编程语言的程序员不会觉得那么突兀了。习惯了Ruby的继承链,总会习惯性的问,这个类的parent是谁?方法是怎么顺着继承链查找的?
下面有一副图,是从StackOverflow上复制过来的。
实例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.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还是有很大的差别。