代码:
有一个制造class的工厂,它支持继承:
var Class = function(parent) {
// 因为class在JavaScript里是保留字,所以用klass代替
var klass = function() {
this.init.apply(this, arguments);
};
// 继承就是要改变这个Class的prototype变量
if (parent) {
var subclass = function() {};
subclass.prototype = parent.prototype;
klass.prototype = new subclass;
// 所以此时klass.prototype.__proto__是parent.prototype了
}
klass.prototype.init = function() {};
// shortcuts for Class
klass.prototype.parent = klass;
return klass;
}
// 制造一个新类
var Animal = new Class;
// 制造另一个类
var Cat = new Class(Animal);
var tom = new Cat;
tom instanceof Cat // true
tom instanceof Animal // true
********* 容易犯错的分割线 *********
简单版:
var Person = function() {};
var clyde = new Person;
之前没仔细看instanceof的定义,比如 clyde instanceof Person
以为是clyde的__proto__链里含有constructor === Person的话就等于true了。
实际上,返回true的原因是Person.prototype === clyde.__proto__;
******************************************
tom.__proto__ === Cat.prototype // 就是subclass
tom.__proto__.__proto__ = Animal.prototype //因为subclass是Animal的实例,subclass.__proto__就等于Animal.prototype
********* 感慨 *********
JavaScript对类,继承的模仿真是难懂……总算搞明白了。就像Quara上那个问题说的那样,现有的JavaScript书,还有Douglas Crockford的那些slides都完全没有提到这样的知识点(好像他们觉得这不是问题似的……)。可是的确有信息被隐藏了,或者说不是那么清晰。怪不得我每次看到这部分都会头疼一下。
总结:
1. 所谓原型链就是指对象上的__proto__链,而不是prototype
2. Contructor(就是那些类函数,首字母大写的)在创建对象的时候会把自己的prototype赋值给对象的__proto__
3. Constructor.prototype有一个默认的熟悉叫做constructor,指向Constructor自己,而且它是可以被篡改的 (比如Cat.prototype就没有constructor属性,它被完全替换成一个subclass实例了)
4. instanceof 是看右值的prototype是否在左值的原型链上(__proto__)
ES5已经提供了Object.isPrototypeOf和Object.getPrototypeOf,所以别使用__proto__了
参考:
JavaScript The Core (反复强烈推荐的啊)
Quora: __proto__与prototype的区别
MDN: instanceof
MDN: constructor