一文详解JavaScript的继承模式
1 原型链继承
#### ES6中通过原型继承多个引用类型的属性和方法,由于原型和实例的关系,即每个构造函数都有自己的原型对象,同时原型有一个属性指向构造函数,并且实例有一个内部的指针指向原型。如果存在某原型是另一个类型的实例时,以此类推。便形成了原型链。
-实现原型链的基本代码模式:
function SubType(){}
SubType.prototype.getValue = function(){}
此时,函数SubType的原型上边定义了一个方法 getValue 在下一步进行实例化的时候,便可以通过这个方法访问函数上的相关属性。
同时,一个函数或者方法的原型可以继承自另外一个函数或者类的实例。
例如:
function SonType(){}
继承自SubType
SonType.prototype = new SubType();
读取实例上的属性的原则:首先会在实例上搜索这个属性,如果未找到,则会搜索继承实例的原型,以此向上,搜索原型的原型。一直持续到原型链的末端。
2 盗用构造函数实现继承
改继承方式可以解决原型包含引用值导致的继承问题,(即可能会导致实现多个不必要的引用或者方法)。
例:
function SuperType(){
this.color = ['red','blue','green']
}
继承自SuperType
function SubType(){ SuperType.call(this) }
let instance = new SubType();
instance.color.push("skyblue)
console.log(instance.color)
red,blue,green,skyblue
;
上述代码展示了盗用构造函数的调用,通过使用call或者apply方法SuperType构造函数能够在实例化SubType的实例时,在其新对象的上下文中执行。
此种方式的优点在于能够在子类的构造函数当中向父类的构造函数传递参数。
SuperType.call(this,'此处传递参数')
缺点在于必须在构造函数中定义方法,函数无法重用,同时子类也无法访问父类原型上的定义的方法。
组合式继承模式
该继承综合了原型链和盗用构造函数继承:将优点集中到一起。
基本思路:通过原型链继承原型上的属性和方法,通过盗用构造函数继承实例属性。
实例代码:
function SuperType(){
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;
}
SubType.ptototype = new SuperType();
SubType.prototype.sayAge = function(){
console.log(this.age)
}
该继承模式弥补了原型链继承和盗用构造函数继承的不足,是使用最多的继承模式,同时还保留了instanceof操作符和isPrototypeOf()方法。
原型式继承
function object(o) {
function F(){};
F.prototype = o;
return new F();
}
object函数会临时创建一个构造函数,将传入的对象赋值个这个构造函数的原型,最后返回这个临时类型的一个实例,本质上,相当于一次浅复制。
ES6中通过增加Object.create()方法实现原型式继承。该方法接收两个参数,1 作为新对象原型的对象。2 给新对象定义额外属性的对象。(可选)
当只有一个参数时,同上文定义的object函数功能相同。
寄生式继承
function createAnother(origin){
let clone = object(origin); 通过调用构造函数创建一个新对象 object函数和原型式继承类似
clone.sayname = function(){ 增强这个新对象的属性和方法
console.log("say hi")
}
return clone;
}
思路类似于:寄生构造函数和工厂模式。创建一个实现继承的函数,以某种方式增强这个对象,最后返回。
寄生式组合继承
组合继承示例:
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);
}
寄生式组合继承
function inheritPrototype(subType,superType){
let prototype = object(superType.prototype); 创建对象
prototype.constructor = subType(); 增强对象
subType.prototype = prototype; 赋值对象
}