本文主要是自己在阅读javascript高级程序设计之后所做的笔记。
js的继承主要依靠原型链的方式实现,与一般的oo语言有些不一样。
原型链
利用原型让一个引用类型继承另一个引用类型的属性和方法。让原型对象等于另一个类型的实例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 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());
|
原型对象等于实例,即使得该对象原型的原型(从图中可以看出)指向实例的原型,从而继承了上一个对象的原型中的属性和方法。
默认原型
所有引用类型都继承了Object
确定原型和实例的继承关系
1 2 3 4 5 6
| alert(instance instanceof Object); alert(instance instanceof SuperType); alert(instance instanceof SubType); alert(Object.prototype.isPrototypeOf(instance)); alert(SuperType.prototype.isPrototypeOf(instance)); alert(SubType.prototype.isPrototypeOf(instance));
|
谨慎定义方法
- 子类型在需要重写超类型中某个方法,或则需要添加超类型中不存在的某个方法。这钟情况下,给原型添加方法的代码一定要放在替换原型的语句之后。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 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; };
SubType.prototype.getSuperValue = function (){ return false; }; var instance = new SubType(); alert(instance.getSuperValue());
|
就如同上面代码中定义顺序一样。
另外需要注意,通过原型链实现继承时,不能通过对象字面量创建原型方法。因为这样会重写原型链。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| 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; }, someOtherMethod : function (){ return false; } }; var instance = new SubType(); alert(instance.getSuperValue());
|
如上所示,就是用字面量的方式定义了原型,那样就重写了原型链。
原型链的问题
引用类型值的问题,前面提过引用类型值会被所有实例共享。而在这里的通过原型来实现继承,原型实际上变成了另一个类型的实例。于是,原先的实例属性也就顺理成章的变成了现在的原型属性。
1 2 3 4 5 6 7 8 9 10 11 12
| function SuperType(){ this.colors = ["red", "blue", "green"]; } function SubType(){ }
SubType.prototype = new SuperType(); var instance1 = new SubType(); instance1.colors.push("black"); alert(instance1.colors); var instance2 = new SubType(); alert(instance2.colors);
|
在创建子类型的实例时,不能向超类型的构造函数中传递参数。
借用构造函数
1 2 3 4 5 6 7 8 9 10 11 12
| function SuperType(){ this.colors = ["red", "blue", "green"]; } function SubType(){ SuperType.call(this); } var instance1 = new SubType(); instance1.colors.push("black"); alert(instance1.colors); var instance2 = new SubType(); alert(instance2.colors);
|
代码中加粗的那一行“借调”了超类型的构造函数。通过call()方法,我们在subtype实例环境下调用了supertype构造函数。
- 传递参数,借用构造函数有一个很大优势,即可以在子类型构造函数中向超类型中传递参数
1 2 3 4 5 6 7 8 9 10 11 12
| function SuperType(name){ this.name = name; } function SubType(){ SuperType.call(this, "Nicholas"); this.age = 29; } var instance = new SubType(); alert(instance.name); alert(instance.age);
|
- 存在的问题
方法都在构造函数中定义,因此函数复用就无从谈起。
组合继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function(){ alert(this.name); }; function SubType(name, age){ SuperType.call(this, name); this.age = age; }
SubType.prototype = new SuperType(); SubType.prototype.constructor = SubType; SubType.prototype.sayAge = function(){ alert(this.age); }; var instance1 = new SubType("Nicholas", 29); instance1.colors.push("black"); alert(instance1.colors); instance1.sayName(); instance1.sayAge(); var instance2 = new SubType("Greg", 27); alert(instance2.colors); instance2.sayName(); instance2.sayAge();
|
在这个例子中, SuperType 构造函数定义了两个属性: name 和 colors 。 SuperType 的原型定义了一个方法 sayName() 。 SubType 构造函数在调用 SuperType 构造函数时传入name 参数,紧接着又定义了它自己的属性 age 。然后,将 SuperType 的实例赋值给 SubType 的原型,然后又在该新原型上定义了方法 sayAge() 。这样一来,就可以让两个不同的SubType 实例既分别拥有自己属性——包括 colors 属性,又可以使用相同的方法了。
另外在javascript高级程序设计上还有3种继承方式,原型式继承和寄生式继承和寄生组合继承。大家可以自己去看。
本文为原创文章,转载请注明出处。
本文地址:http://hiluluke.cn/2015/10/14/js-inherit/