许多面向对象语言都支持两种继承: 接口继承和实现继承。ECMAScript只支持实现继承,而且实现继承主要是依靠原型链来实现的
1.原型链
基本思想是利用原型 让一个引用类型 继承 另一个引用类型的方法和属性。
每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,每个实例都包含一个指向原型对象的内部指针。
原型链的基本概念: 让原型对象等于另一个类型的实例。
|
function SuperType(){ this.property = true; } SuperType.prototype.getSuperValue = function(){ return this.property; }; function SubType(){ this.subproperty = false; } SubType.prototype = new SuperType(); SubType.prototype.getSubValue = function(){ return this.subproperty; } var instance = new SubType(); alert(instance.getSuperValue()); //true |
所有引用类型都默认都继承了Object,而这个继承也是通过原型链来实现的。所有函数的默认原型都是Object的实例,因此默认原型都会包含一个内部指针指向Object.prototype。这也正是所有自定义类型都会继承toString()、valueOf()等默认方法的原因。
可以通过两种方法来确定原型和实例之间的关系。
1. instanceof操作符 2. isPrototypeOf()方法:
alert(instance instanceof Object); //true alert(instance instanceof SuperType); //true alert(instance instanceof SubType); //true |
alert(Object.prototype.isPrototypeOf(instance)); //true alert(SuperType.prototype.isPrototypeOf(instance)); //true alert(subType.prototype.isPrototype(instance)); //true |
子类型有时候需要覆盖父类型中的某个方法,或者需要添加一个新的方法,不管怎样,给原型添加方法的代码一定要放在 SubType.prototype = new SuperType(); 语句之后。
原型链的问题:
function SuperType(){ this.colors = ["red", "blue", "green"]; } function SubType(){ } SubType.prototype = new SuperType(); var instance1 = new SubType(); instance1.colors.push("black"); alert(instance1.colors); //red,blue,green,black var instance2 = new SubType(); alert(instance2.colors); //red,blue,green,black
在这个例子中,SuperType构造函数定义了一个colors属性,该属性包含一个数组(引用类型值)。 SuperType的每个实例都会有自己的colors属性。 当SubType通过原型链继承了SuperType之后,SubType.prototype就变成了SuperType的一个实例, 因此也拥有一个他自己的colors属性,和 SubType.prototype.colors 创建方式一样。所以SubType的所有实例都会共享这一个colors属性。
原型链的第二个问题是: 在创建子类型的实例时,不能向父类型的构造函数中传递参数。