1.原型继承
function SuperType(){
this.property = "SuperType";
}
SuperType.prototype.getValue = function(){
return this.property;
}
function SubType(){
this.subproperty ="SubType";
}
//继承SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function(){
return this.subproperty;
};
var sub = new SubType();
alert(sub.getValue()); //SuperType,输出继承而来的函数
alert(sub.getSubValue()); //SubType,输出本身定义的函数
继承是通过创建SubType.prototype = new SuperType(); SuperType实例,赋给SubType.prototype。实现的本质是重写原型对象,
var sub = new SubType();创建SubType实例,新原型就是这个实例,这个新原型中不但拥有SuperType所有属性和方法
注意:通过原型链实现继承时不能使用字面量创建原型方法,因为这样做会重写原型链
原型链的问题
1.引用类型值的原型属性被所有实例共享,一个实例的修改也会改变其他实例的值
2.在创建子类型的实例时,不能向超类型的构造函数中传递参数。
2.借用构造函数(伪造对象或是经典继承)
基本思想很简单,在子类型构造函数的内部调用超类型构造函数。
function SuperType2(){
this.colors = ["red", "blue", "black"];
}
function SubType2(){
//继承SuperType2
SuperType2.call(this);
}
var instance1 = new SubType2();
instance1.colors.push("yellow");
alert(instance1.colors);//输出red,blue,black,yellow
var instance2 = new SubType2();
alert(instance2.colors);//输出red,blue,black
2.传递参数
借用构造函数一大优势就是子类型向超类型传递数据
//借用构造函数
function SuperType2(name){
this.colors = ["red", "blue", "black"];
this.name =name;
}
function SubType2(){
//继承SuperType2
SuperType2.call(this,"Dnery");
this.age = 29;
}
var instance1 = new SubType2();
instance1.colors.push("yellow");
alert(instance1.colors);
var instance2 = new SubType2();
// alert(instance2.colors);
alert(instance2.name);
alert(instance2.age);</pre>
借用构造函数问题
方法都在构造函数中定义,没有函数复用,而且在超类型中定义的方法,子类型中是不可见的,结果所有类型只能用构造函数模式。
所以很少单独使用
3.组合继承(最常用的继承方式)
也叫伪经典继承,指的是将原型链和借用构造函数的技术组合到一块。
背后思路是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。
这样,即通过在原型上定义方法实现了函数复用,又能够保证每个实例都有它自己的属性。
//组合继承
function SuperType3(name){
this.name = name;
this.colors = ["red","green"];
}
SuperType3.prototype.sayName = function(){
alert(this.name);
}
function SubType3(name, age){
//继承属性
SuperType3.call(this,name); //第二次调用,创建了实例属性,所以覆盖掉了第一次调用原型上面的属性
this.age =age;
}
SubType3.prototype = new SuperType3(); //第一次调用
SubType3.prototype.constructor= SubType3;
SubType3.prototype.sayAge = function(){
alert(this.age);
}
var ins1 = new SubType3("denry","23");
ins1.colors.push('red');
alert(ins1.colors);
ins1.sayName();
ins1.sayAge();
var ins2 = new SubType3("denry","23");
alert(ins2.colors);
ins2.sayName();
ins2.sayAge();
4.原型式继承
必须有一个对象作为另一个对象的基础,把基础对象传递给对象,然后再根据具体需求加以修改即可。新对象相当于创建基础对象的副本
ECMASCRIPT5 新增的Object.create()方法规范了原型式继承
var person = {
name:'denry',
firends:['A','B','C']
};
var aPerson = Object.create(person);
aPerson.name = "BBB";
aPerson.firends.push("D");
var bPerson = Object.create(person);
bPerson.name = "CCC";
bPerson.firends.push("E");
alert(aPerson.firends); //A,B,C,D,E
在保持一个对象与另一个对象相似的情况下,原型式继承是完全可以胜任的。
注意:包含引用类型的值始终会共享相应的值,就像使用原型模式一样
5.寄生式继承
即创建一个用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后在像真的是它做了所有工作一样返回对象
//5.寄生式继承
function createAnother(original){
var clone = Object(original);
clone.sayHi = function(){
alert("Hi");
};
return clone;
}
var person4 = {
name:'Denry',
friends:["A","B","C"]
}
var aPerson4 = createAnother(person4);
aPerson4.sayHi(); //Hi
上面的例子基于person4对象返回了一个新对象
在主要考虑对象而不是自定义类型和构造函数的情况下,寄生式继承是一种有用的模式。
6.寄生组合式继承
组合继承会调用两次构造函数,
背后思路:不必为了指定子类型的原型而调用超类型的构造函数。本质上,就是使用寄生式继承来继承超类型的原型。
function SuperType6(name){
this.name = name;
this.colors = ["red","green"];
}
SuperType6.prototype.sayName = function(){
alert(this.name);
}
function SubType6(name, age){
// 借用构造函数来实现对实例属性的继承
SuperType3.call(this,name);
this.age =age;
}
//原型链实现对原型属性和方法的继承
function inhert(SubType6,SuperType6){
var pro = Object(SuperType6.prototype); //创建对象
pro.constructor = SubType6; //增强对象,弥补因重写原型失去的constructor属性
SubType6.prototype = pro; //指定对象
}
inhert(SubType6, SuperType6);
var test = new SubType6("哈哈",0);
test.sayName();
只调用了一次构造函数,认为寄生组合式继承是引用类型最理想的继承范式。
1 条评论
技术原理阐述透彻,配图辅助理解到位。