几种基于原型链的继承方式
ECMASCript只支持实现继承,主要是依靠原型链来实现的。
实现一个简单的原型链
//SuperType类型
function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue = function (){
return this.property
}
//SubType类型
function SubType(){
this.subproperty = false;
}
// 重写了原型对象,SubType继承了SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function (){
return this.subproperty;
}
let instance = new SubType();
// 注意instance能使用SuperValue的方法
console.log(instance.getSuperValue())//true所有引用类型默认继承了Object,而所有函数的默认原型都是Object的实例。
console.log(instance instanceof Object);//true console.log(instance instanceof SuperType);//true console.log(instance instanceof SubType);//true
也可以使用isPrototypeOf()方法
console.log(Object.prototype.isPrototypeOf(instance)); console.log(SuperType.prototype.isPrototypeOf(instance)); console.log(SubType.prototype.isPrototypeOf(instance));
注意通过原型链实现继承的时候,不要使用对象字面量创建原型方法。因为这样就会重写原型链,导致继承关系失效。
原型链第一个问题就是原型链会导致继承的prototype的属性会“共享”,实例之间会相互影响,第二问题就是无法在不影响其他实例情况下给超类的构造函数传参。实际上很少单独使用原型链。
1.组合继承
function SuperType(name){
this.name=name;
this.color=['red','blue','green'];
}
SuperType.prototype.sayName = function (){
console.log(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 (){
console.log(this.age)
};
let instance1 = new SubType("nick", 29);
instance1.color.push("black");
console.log(instance1.color);
instance1.sayName();
instance1.sayAge();
let instance2 = new SubType("grep", 27);
console.log(instance2.color);
instance2.sayName();
instance2.sayAge();2.原型式继承
// 对参数o进行一次浅复制
function object(o){
function F(){}
F.prototype = o;
return new F()
}
// 作为另一个对象的基础
let person = {
name:"nick",
friends:['shellby','court','van']
};
let person2 = object(person);
person2.name = 'grep';
person2.friends.push("Rob");
let person3 = object(person);
person3.name = 'lina';
person3.friends.push("Barbie");
console.log(person.friends)//[ 'shellby', 'court', 'van', 'Rob', 'Barbie' ] person2和person3有着与person一样的共享属性
ES5中使用Object.create来替代object方法,并且可以传入第二个参数,一个为新对象定义额外属性的对象。
3.寄生式继承
function createAnother(ori){
// 创建一个新对象
let clone = Object.create(ori);
// 增强这个对象
clone.sayHi = function (){
console.log("hi")
};
return clone
}
let person = {
name:"nick",
friends:['shell','court','van']
};
let person1 = createAnother(person);
person1.sayHi();
4 寄生组合式继承
组合继承的缺点就是会两次调用父类的构造函数,可以直接使用父类原型的复制副本。
// 子类构造函数和父类构造函数
function inheritPrototype(subType,superType){
let prototype = Object.create(superType.prototype);
prototype.constructor = subType;
subType.prototype = prototype
}
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)
this.age = age
}
// 实际上就是复制父类的prototype方法
inheritPrototype(SubType,SuperType);
SubType.prototype.sayAge = function (){
console.log(this.age)
}
let instance = new SubType('nick', '29')
console.log(instance.colors,instance.name,instance.age)
instance.sayAge()
let instance2 = new SubType('grep', '27')
console.log(instance2.colors,instance2.name,instance2.age)
instance2.sayAge()这样只需要每次调用一次构造函数就行了。