一.原型链继承
首先,原型链是什么?每一个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。让原型对象等于另一个类型的实例,此时的原型对象将包含一个指向另一个原型对象的指针,而另一个原型对象中也包含一个指向;另一个构造函数的指针。如此层层递进,就构成了实例与原型的链条。
function SuperType(){
this.name = '超类型';
this.colors = ['red','blue','green'];
}
SuperType.prototype.age = 10; //给SuperType添加原型属性
function SubType(){
}
SubType.prototype = new SuperType();
var instance1 = new SubType();
console.log(instance1.age); // 10
SubType继承了SupType,而继承是通过创建SupType的实例,并将该实例赋值给SubType.prototype.
function SuperType(){
this.name = '超类型';
this.colors = ['red','blue','green'];
}
SuperType.prototype.age = 10; //给SuperType添加原型属性
function SubType(){
}
SubType.prototype = new SuperType();
var instance1 = new SubType();
instance1.colors.push('black')
var instance2 = new SubType();
console.log(instance2.colors); // ["red", "blue", "green", "black"]
缺点:
1.新实例无法向父类构造函数传参
2.SuperType的colors属性包含一个数组(引用类型值),SubType.prototype继承SuperType实例后;SubType的所有实例都会共享colors属性。(包含引用类型值的属性始终都会共享相应的值)
二.借用构造函数继承
function SuperType(name){
this.name = name;
this.colors = ['red','blue','green'];
}
SuperType.prototype.age = 10; //给SuperType添加原型属性
function SuperType1(sex){
this.sex = sex;
}
function SubType(){
SuperType.call(this, 'SubType');
}
var instance1 = new SubType();
instance1.colors.push('black')
var instance2 = new SubType();
console.log(instance1.name) //SubType
console.log(instance2.colors); // ["red", "blue", "green"]
console.log(instance1.sex) //男
console.log(instance2 instanceof SuperType);// false
特点:
1.通过使用apply()和call()方法在新创建额对象上执行构造函数
2.在子实例中可向父实例传参
3.解决了原型链继承的问题
4.可以继承多个构造函数属性(call多个)
缺点:
1.果仅仅是借用构造函数,那么也将无法避免构造函数模式存在的问题——方法都在构造函数中定 义,因此函数复用就无从谈起了
2.在父类型的原型中定义的方法,对子类型而言也是不可见的,结果所有类型只能使用构造函数模式
三.组合继承
组合继承的思路是使用原型链继承实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承
function SuperType(name){
this.name = name;
this.colors = ['red','blue','green'];
}
SuperType.prototype.sayName =function(){
console.log(this.name);
}
function SubType(name,age){
SuperType.call(this,name);// 第二次调用SuperType();
this.age = age;
}
SubType.prototype = new SuperType();// 第一次调用SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
console.log(this.age);
}
var instance1 = new SubType('instance1',10);
instance1.colors.push('black');
console.log(instance1.colors);// ["red", "blue", "green", "black"]
instance1.sayName();//instance1
instance1.sayAge();//10
var instance2 = new SubType('instance2',11);
console.log(instance2.colors);// ["red", "blue", "green"]
instance2.sayName();//instance2
instance2.sayAge();//11
特点:结合了原型链继承和借用构造函数继承的优点
缺点:
无论在什么情况下,都会调用两次父类构造函数
四.原型式继承
原型式继承继承本质是通过调用函数,然后在函数内部先创建一个临时性的构造函数,然后将传入的对象作为这个构造函数的原型,最后返回这个临时类型的一个新的构造函数。函数对传入其中的对象执行了一次浅复制
function object(o){ //Object.create()在传入一个参数下,行为相同
function F(){}; //先创建一个临时性的构造函数
F.prototype = new o();//
return new F();
}
var person ={
name:'person',
colors:['red','blue','green']
}
var anotherPerson = object(person);
console.log(anotherPerson.name); // person
Object.create()接收两个参数,一个用作新对象原型的对向和一个为新对象定义额外属性的对向。在传入一个参数的情况下下,与object()的行为相同
var newPerson = Object.create(person,{
age:{
value: 10
}
})
console.log(newPerson.age); // 10
缺点和原型链继承相似
五.寄生式继承
function object(o){ //Object.create()在传入一个参数下,行为相同
function F(){}; //先创建一个临时性的构造函数
F.prototype = o;//
return new F();
}
function createAnother(orgiginal){
var clone = object(orgiginal);//通过调用函数创建一个新的对象
clone.sayHi = function(){ //以某种方式来增强这个对象
console.log(this.name);
}
return clone;//返回这个对象
}
var person = {
name:'Nicholas',
friends:['aa','bb','cc']
}
var anotherPerson = createAnother(person);
anotherPerson.sayHi(); // Nicholas
在主要考虑对象而不是自定义类型和构造函数的情况下,寄生式继承也是一种有用的模式。示范使用的object()函数不是必须的;任何能够返回新的对象的函数都适用于此模式
缺点:函数不能复用
六.寄生组合式继承
寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。其背后的基本思路是:不必为了指定子类型的原型而调用超类型的构造函数,我们所需要的无非就是超类型原型的一个副本而已。本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。
function inheritPrototype(subType, superType){
var prototype = Object(superType.prototype); //创建对象
prototype.constructor = subType;//增强对象
subType.prototype = prototype; // 指定对象
}
function SuperType(name){
trhis.name = name;
this.colors = ['red','blue','green'];
}
SuperType.prototype.sayName=function(){
console.log(this.name);
}
function SubType(name,age){
SuperType.call(this,name);
this.age = age;
}
inheritPrototype(SubType,SuperType);
inheritPrototype函数示例中,接收两个参数:子类型构造函数和超类型构造函数。在函数内部,第一步是创建超类型原型的一个副本。第二步是为了创建的副本添加constructor属性,从而弥补重新原型而失去默认的constructor属性。最后一步,将创建地 对象赋值给子类型的原型。
优势:解决了组合继承两次调用超类型构造函数
Javascript主要通过原型链实现继承。原型链的构建是通过将一个类型的实例赋值给另一个构造函数的原型实现的。
网友评论