继承是面向对象编程中另一个非常重要的概念。JavaScript支持继承,但不支持接口继承。继承主要靠原型链。
原型链
首先,我们必须了解什么是原型链,并在一篇文章中详细解释它,以了解原型和原型之间的关系和区别
原型链继承的基本思想是让一个原型对象指向另一个类型的实例
function SuperType(){ this . property=true } SuperType . prototype . getSuperVaLue=function(){ return this . property } function SuperType(){ this . sub property=false } SuperType . prototype=new SuperType()SuperType . prototype . getSuperVaLue=function(){ return this . sub property } The varinstance=NewSubsType()console . log(实例getsupervalue ())//true代码定义了两种类型,SuperType和subtype。每种类型分别有一个属性和一个方法。SubType继承SuperType,继承是通过创建SuperType的实例并将其分配给SubType.prototype来实现的。
实现的本质是重写原型对象,并用新类型的实例替换它。那么SuperType存在的实例中的所有属性和方法也存在于SubType.prototype中。
正如我们所知,当一个实例被创建时,实例对象中会有一个内部指针,指向创建它进行关联的原型。这里,代码SubType.prototype=new SuperType()还将在SubType.prototype中创建一个内部指针,以将SubType.prototype与SuperType相关联。
因此,实例指向SubType的原型,SubType的原型指向SuperType的原型,然后当实例调用getSuperValue()方法时,它将沿着这条链一直向上。
添加方法
向子类型原型添加方法时,如果父类具有相同的名称,子类型将重写方法以达到新的目的。但是这个方法仍然存在于父类中。
记住,不能以字面形式添加,因为上面说了按实例继承本质上是重写,再用字面形式就是另一种重写,但这种重写与父类无关,所以会导致原型链截断。
function SuperType(){ this . property=true } SuperType . prototype . getSuperVaLue=function(){ return this . property } function SubType(){ this . subproperty=false } SubType . prototype=new SuperType()SubType . prototype={ getSuperValue : function(){ return this . subproperty } } var实例=new SubType()console . log(instance . getSuperVaLue())//错误问题
简单地使用原型链继承,主要问题来自于包含引用类型值的原型。
function SuperType(){ this . colors=[' red ',' blue ',' green ']} function SuperType(){ } SuperType . prototype=new SuperType()var instance 1=new SuperType()instance 1 . colors . push(' black ')console . log(instance 1 . colors)/[' red ',' blue ',' green ',' black ']console . log(instance 2 . colors)/[' red ',' blue ',' Green ',' black '在SuperType构造函数中定义一个colors属性。当通过原型链继承SubType时,这个属性将出现在SubType.prototype中,就像SubType.prototype.colors是专门创建的一样,这将导致SubType的所有实例共享这个属性。因此,如果instance1修改了颜色的参考类型值,它也会反映在instance2中。
借用构造函数
该方法旨在解决原型中引用类型值带来的问题。
这个方法的思想是调用子类构造函数内部的父类构造函数,对象的执行上下文可以通过apply()和call()方法来改变
function supertype(){ this . colors=[' red ',' blue ',' Green ']} function SuperType(){//继承SuperType SuperType . call(this)} varinstance 1=new SubType()varinstance 2=new SubType()instance 1 . colors . push(' black ')console . log(instance 1 . colors)/[' red ',' blue ',' black ']console . log(instance 2 . colors)//[' red ',' blue ',Green]创建新的SuperType实例时,会调用SuperType构造函数,因此所有对象
因此,每个子类型实例都有自己的颜色属性副本。
传递参数
使用构造函数的另一个优点是可以传递参数
函数超类型(名称){this。name=name}函数子类型(){//继承SuperType SuperType.call(this,Jiang') this。job=' student ' } var instance=new subtype()console . log(instance . name)//jiangconsole . log(instance . job)//学生问题
如果只使用构造函数,则方法是在构造函数中定义的,因此不能重用该函数
组合继承(原型链构造器)
组合继承是原型链继承与构造函数相结合的模式,以充分发挥它们的优势。
思路是用原型链继承原型属性和方法,借用构造函数继承实例属性。
这样,在原型上定义的方法不仅实现了功能重用,还保证了每个实例都有自己的属性。
函数SuperType(name){ this . name=name this . colors=[' red ',' blue ',' Green ']} SuperType . prototype . say name=function(){ console . log(this . name)}函数子类型(name,job){//继承属性SuperType.call(this,The name) this.job=job} //继承方法子类型。原型=新的子类型()子类型。原型。构造函数=supertypesubtype。原型。say job=function(){ console . log(this . job)} var instance 1=new SubType(' Jiang ',' student ')instance 1 . colors . push(' black ')console . log(instance 1 . colors)/[' red ',' blue ',' green ',' black ']instance 1 . say name()/' Jiang ' instance 1 . say job()/' student ' var instance 2=new SubType(' J ',' Doctor') console。日志(实例2。颜色)////['红色','蓝色','绿色']实例2。say name()//“j”instance 2。sayjob ()//'doctor '这种模式避免了原型链和构造函数继承的缺陷,并对它们进行了集成
原型继承
Prototype可以基于现有对象创建新对象,而无需创建自定义类型。
function object(o){ function f(){ } f . prototype=o return new f()}在object function内部创建一个临时构造函数,然后将传入的对象作为这个构造函数的原型,最后返回这个临时类型的一个新实例。
本质上,对象执行传递给它的对象的浅拷贝。
Var person={name:' Jiang ',friends 3360[' shelby ',' court ']} var other person=object(person)console . log(other person。朋友)//['谢尔比','法院']你必须有一个对象来经历这个模式
在这个例子中,作为另一个对象的基础,person被传递到object中,函数将返回一个新的对象。
这个新对象以人为原型,所以它的原型包含一个基本类型和一个引用类型。
因此,如果有另一个对象与person相关联,当otherPerson修改数组friends时,它也会反映在这个对象中。
Object.create()方法
ES5通过Object.create()方法标准化原型继承,可以接受两个参数,一个是用作新对象原型的对象,另一个是为新对象定义附加属性的可选对象。行为相同,基本用法与上述对象相同,只是对象不能接受第二个参数。
Var person={name:' Jiang ',friends 3360[' shelby ',' court ']} var other person=object。创建(个人)控制台。记录(另一个人。朋友)//['谢尔比','宫廷']寄生继承
寄生继承的思想类似于寄生构造函数和工厂模式,即创建一个只封装继承过程的函数。
函数create other(o){ Var clone=object . create(o)//创建一个新的对象clone . sayHi=function(){//add the method console . log(' hi ')} return clone//return this object } Var person={ name : ' Jiang ' } Var other Pearson=create other(person)other Pearson . sayhi()根据person返回一个新的对象other Pearson,它不仅有person的属性和方法,还有自己的sayhi方法。
当主要考虑对象而不是自定义类型和构造函数时,这是一种有用的模式。
寄生组合遗传
在前面提到的组合模式(原型链构造函数)中,继承时需要调用两次父类构造函数。
父类
函数超类型(名称){this。name=namethis。colors=['red ',' blue ',' green']}第一次出现在子类构造函数中
函数SubType(名称,作业){//继承了属性SubType。称这个为。job=job}第二次将子类的原型指向父类的实例
//继承方法SubType.prototype=new SuperType()。当使用var instance=new SubType()时,将生成两组名称和颜色属性,一组在SubType实例上,另一组在SubType原型上,但实例上的属性会屏蔽原型上的属性。
这个问题可以通过使用寄生组合模式来规避。
这种模式通过借用构造函数来继承属性,通过混合原型链来继承方法。
基本思想:我们不必为了指定子类型的原型而调用父类的构造函数。我们需要的只是父类原型的副本。
本质上,寄生继承用于继承父类的原型,结果被分配给子类型的原型。
该函数继承原型(子类型,超类型){var prototype=object。创建(超类型。原型)原型。构造函数=子类型子类型。prototype=prototype}这个函数实现了最简单的寄生组合继承形式。
这个函数接受两个参数,一个子类和一个父类。
第一步是创建父类原型的副本,第二步是向创建的副本添加构造函数属性,第三步是将子类的原型指向这个副本。
function SuperType(Name){ this . Name=Name this . colors=[' red ',' blue ',' Green ']} SuperType . prototype . say Name=function(){ console . log(this . Name)} function subtype(Name,job){//继承属性SuperType.call(this,Name) this.job=job} //继承原型(subtype,SuperType)var instance=new subtype(' Jiang ',' student') instance。sayname()补充:使用Object.create直接实现就是将上面封装的函数进行反汇编,这样演示可以更容易理解。
函数SuperType(name){ this . Name=Name this . colors=[' red ',' blue ',' Green ']} SuperType . prototype . say Name=function(){ console . log(this . Name)}函数子类型(Name,job){//继承属性SuperType.call(this,Name) this.job=job} //继承子类型。原型=对象。创建(超类型。prototype)//修复构造函数subtype . prototype . constructor=subtype var instance=new subtype(' Jiang ',' student') instance.sayname () es6增加了一个新方法Object.setPrototypeOf,可以直接创建关联,无需手动添加构造函数属性。
//inherit object . set prototype of(subtype . prototype,supertype . prototype)console . log(subtype . prototype . constructor===subtype)//true以上是边肖介绍的JavaScript的六种继承方法(推荐)。希望对大家有帮助。如果你有任何问题,请给我留言,边肖会及时回复你。非常感谢您对我们网站的支持!