宝哥软件园

彻底理解js面向对象继承

编辑:宝哥软件园 来源:互联网 时间:2021-09-01

说起这种继承,懂面向对象的朋友都知道,大多数oo语言有两种,一种是接口继承(只继承方法签名);一种是实现继承(继承实际的方法)

但是js中没有签名,所以只实现了继承,通过原型链实现。让我们正式讨论js中的继承

1、原型链

原型链:实现继承的主要方法,利用原型使一个引用类型继承另一个引用类型的属性和方法。

回顾:构造函数、原型和实例之间的关系

每个构造函数都有一个原型对象(人。原型);原型对象都包含指向构造函数的指针);每个实例都包含一个指向原型对象的指针(不可见的原型指针)

原型链是怎么来的?

构造函数的原型对象是另一个构造函数的实例;此构造函数的原型对象将有一个(不可见的_proto_指针)指向另一个构造函数的原型对象;

然后当另一个原型对象是另一个构造器实例时会发生什么,于是它一层一层地前进,形成一个原型链;让我们具体看一下

//第一个构造函数;有一个属性和一个原型方法functionsupertype () {this。属性=true} super type . prototype . getsuper value=function(){ return this . property }//第二个构造函数;目前有一个属性functionsubtype () {this。subproperty=false }//它继承了SuperTypeSubType原型成为SuperType的实例;其实就是重写SubType的原型对象;遗传亚型。prototype=new SuperType()//到SuperType原型对象。现在这个构造函数有两个属性(一个是自己的子属性,一个是带有原型对象的继承属性)。两种方法(原型对象的getSubValue,原型对象的原型对象的Getsupervalue)subtype . prototype . getSubValue=function(){ return this . subproperty } var instance=new subtype()//创建第二个构造函数实例控制台。日志(实例。getSupervalue())//true;首先找出实例中是否存在此方法;显然不是,找出SubType原型对象是否有这个方法;否,查找SubType原型对象的原型对象;显然有一个注意事项:实例的构造函数现在指向SuperType构造函数;因为原始的SubType.prototype已经被重写,所以它的内部构造函数指向构造函数SuperType以及SubType.prototype的原型对象的构造函数;至于原型搜索机制是如何工作的,请仔细看看上面的代码,相信可以

1.1完整的原型

我已经在原型部分提到了一些东西。再说一遍。一个完整的原型包括对象。

所有函数的默认原型都是对象的实例;每个默认原型都有一个指向对象原型的指针;因此,自定义类型继承诸如toString和valueOf之类的方法

而Object.prototype的_proto_指针指向空值以结束原型链。以Person构造函数为例,查看完整的原型链图

1.2原型与实例的关系

第一个使用instanceof运算符:出现在测试用例和原型链中的构造函数,结果为真

第二种方法是isPrototypeOf():只要原型已经出现在原型链中,就可以说是从原型链中派生出来的实例的原型

Console.log(对象的实例实例)//为true console.log(超类型的实例实例)console.log(子类型的实例实例)console.log(对象。prototype . is prototype of(instance))//都是真正的console.log (supertype。prototype.isprototypeof(实例))console.log(子类型。prototype . is prototype of(instance))1.3仔细定义方法

注意:向原型对象添加方法必须放在替换原型后面,因为在替换原型之前找不到方法,原型会被重写;

注意:通过原型链继承时,不能使用对象文字创建原型方法,因为原型链也会被重写。

函数SuperType(){ this。属性=true} SuperType。原型。GetSuperVaLue=function(){返回这个。property } function SuBject(){ this。sub属性=false }//继承SuperType SupLe。prototype=new SuperType()//使用字面量添加新方法,导致上一行无效因为现在的原型替换了目标实例而非超类型的实例,关系中断亚型。prototype={ getsubvalue e : function(){ return this。子属性;},somother method : function(){ return false } };var实例=new SupLe()。控制台。日志(实例。getsuper value())//错误1.4原型链的问题

1、包含引用类型值的原型:当实例是另一函数的原型时,引用类型值就会变成原型上的属性,就会被另一函数的实例所共享。

函数SuperType(){ this。colors=['黄色','红色','橄榄]}函数SuperType(){ } SuperType。prototype=new SuperType()//color实际上就是原型上的了var实例1=新的SubType()实例1。颜色。推动('紫色)var实例2=new SubType()控制台。日志(实例1。colors==实例2。颜色)//真2、创建子类型实例时,不能向超类型的构造函数传递参数(没有办法在不影响所有对象实例的情况下,给超类型的构造函数传递参数)

2、借助构造函数

为了解决原型中包含引用类型值带来的问题,利用构造函数来解决

在子类型构造函数的内部调用超类型构造函数(函数是特定环境中执行代码的对象,可以通过应用或呼叫调用)

函数SuperType(){ this。color=['黄色','红色','橄榄]}函数SuperType(){//继承了超类型超类型。调用(this)} var实例1=new SubType()实例1。颜色。推动('紫色)var实例2=new SubType()控制台。日志(实例1。颜色)/['黄色','红色','橄榄色','紫色]控制台。日志(实例2。颜色)//['黄色','红色','橄榄色'] //传递参数函数SuperType(name){ this。name=name }函数SuperType(){ SuperType。称(这个为‘double’)这个。age=12 } var实例1=new SuperType()控制台。日志(实例1。名称)//双控制台。日志(实例1。年龄)//12问题:仅仅借鉴构造函数,那么避免不了构造函数的问题,方法都在构造函数定义了,函数无法复用

3、组合继承(常用的还是组合,和原型与构造结合一样)

函数父类型(名称){ this。name=namethis.color=['黄色','红色','橄榄'];} SuperType。原型。SayName=function(){ console。日志(这个。姓名);}功能子类型(姓名、年龄){ //继承属性,创建属性副本SuperType.call(this,name);this.age=年龄;} //继承属性和方法,只是原型中属性被后来的函数调用生成的属性副本遮盖亚型。prototype=new SuperType();警报(SupLe。原型。构造函数)//指向的是父类型子类型。原型。构造函数=SuBype//将构造器回归到图表类型构造函数身上子类型。原型。说age=function(){ console。日志(这个。age)} var实例1=new SubType(' double ',23)实例1。颜色。按下(粉色)控制台。日志(实例1。颜色)/['黄色','红色','橄榄','粉色]实例1。说出name()//双实例1。比方说age()//23 var实例2=new SubType(' single ',34)控制台。日志(实例2。颜色)/['黄色','红色','橄榄]实例2。说.还有其他的继承,花点时间写一下

1、原型式继承

克罗克福德写的;借助原型可以基于已有的对象创建新对象,同时不必创建自定义类型

函数对象(o){ //本质上对象()函数对其中对象的浅复制函数F(){} //创建一个新的构造函数F.prototype=o //构造函数原型为传入的对象返回新的F() //返回构造函数的实例} var person={ name:'double ',friends 3360[' Tom ',' jack ',' Mike ']} var person 1=object(person)//事实上为原型共享人1。姓名='灰色'人1。朋友。按压(“单”)控制台。日志(人1。朋友)/['汤姆','杰克','迈克','单身']var person 2=object(人)person 2。name=' red '控制台。日志(人员2。朋友)//['汤姆','杰克','迈克','单身' ES5为了规范原型式的继承,有个Object.create()来方便,IE9以上可以;只是想一个对象和另一个对象保持类似的情况,完全可以这种方法

var person={ name:'double ',friends 3360[' Tom ',' jack ',' Mike ']} var person 1=object。创造(人)人1。姓名='单身'人1。朋友。push(' singles ')var person 2=object。创建(个人)控制台。日志(人1。朋友==人2。朋友)//真//对象。创建()接受两个参数,一个为作为新对象原型的对象,一个为新对象定义额外属性对象var person={ name:'double ',friends 3360[' Tom ',' jack ',' Mike ']} var person 1=object。create(person,{ name : { value : ' single '//每个属性都是通过自己描述符定义的} })2、寄生式继承

思路和原型式继承一脉相承,创建一个用于封装继承过程的函数,内部通过方式增强对象,返回对象;主要考虑对象时使用

函数对象(o){函数F(){} F.prototype=o返回新的F() }函数createPerson(原始){ var clone=object(原始)//继承原型克隆人。say name=function(){ alert(' name ')}返回克隆} var person={ name : ' double ',friends 3360[' single ',' tom ',' jack ']} var person 1=createPerson(person)person 1。说出姓名()//姓名引用类型值还是共享的3、寄生组合继承

组合继承是继承中常常用到的,但是会调用两次超类型构造函数;寄生组合继承就是为了解决这个问题的

函数对象(o){函数F()} { F .原型=o返回新的F()}函数继承原型(subType,SuperType){ var prototype=object(SuperType)//创建对象(超类型实例)原型。构造函数=subType//增强对象subType.prototype=prototype //指定对象(原型赋予实例)}函数SuperType(姓名、性别){ this。name=为此命名。性=性这个。colors=[' red ']} SuperType。原型。说出name=function(){ alert(this。name)} function SuperType(姓名、性别、年龄){ SuperType.call(this,姓名、性别)this。age=age }继承原型(SuperType,SuperType) //目前子类型。原型什么都没有亚型。原型。SayAge=function(){//为子类型。原型添加个方法警惕(这个。age)} var person 1=new SubType(' double ',' man ',34)控制台。日志(人1。名称)//SuperType这是个bug控制台。日志(人1。性)//男人控制台。日志(人1。颜色)/['红色']人1。sayage()//34到此,差不多结束啦,感谢你对我们的支持,希望我们整理的内容能够帮助到你。

更多资讯
游戏推荐
更多+