手机版

详细说明JavaScript使用原型和原型链实现对象继承的方法

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

本文阐述了JavaScript使用原型和原型链实现对象继承的方法。分享给大家参考,如下:

其实JavaScript并不是面向对象的语言,但是JavaScript是基于原型链和函数语法的继承,使得编程相当灵活,所以可以利用原型链实现面向对象编程。

以前,我对JavaScript知之甚少。这两天看了原型链,练习了JavaScript的对象继承。

以下是原型链和原型的关系,引用了网上的一张图片

在Javascript中,每个函数都有一个指向自己原型的原型属性prototype,这个函数创建的object也有一个指向这个原型的原型属性,函数的原型就是一个对象,所以这个对象也有一个指向自己原型的原型,这个原型一层一层深入到Object对象的原型中,从而形成一个原型链。

-基本继承模式

函数父类(){ this.type='父';}父类. prototype . GetYep=function(){ console . log(this . type);}父类. prototype . obj={ age : 35 };函数child class(){ this . type=' child ';}ChildClass.prototype=父类();child class . prototype . GetType=function(){ console . log(this . type);}var父亲=new父类();var child=new child class();父亲. GetYep();child . GetType();这种方法有优点也有缺点。继承的实现非常简单,代码简单易懂。但是子类继承父类的成员变量,需要自己重新初始化,这就相当于父类有多少成员变量,需要在子类中重新定义和初始化

函数父类(type) { this.type=type || '父';}函数child class(type){ this . type=type | | ' child ';}ChildClass.prototype=父类();child class . prototype . GetType=function(){ console . log(this . type);}var父亲=新父亲类(' FatClass ');var child=new child class(' child class ');在上述情况下,只需要初始化name属性,如果初始化工作不断增加,就非常不方便了。因此,有如下改进方法。

-借用构造函数

var Parent=function(name){ this . name=name | | ' Parent ';} ;parent . prototype . getname=function(){ return this . name;} ;parent . prototype . obj={ a : 1 };var Child=function(name){ parent . apply(this,arguments);} ;子原型=父原型;var parent=新父代(' my Parent ');var Child=new Child(' my Child ');console . log(parent . getname());//myparentconsole . log(child . getname());//myChild,我们只需要在子类的构造函数中执行一次父类的构造函数,就可以同时继承父类原型中的属性,这更符合原型的初衷,就是把可重用的内容放在原型中,只继承原型中的可重用内容。

-临时构造器模式(圣杯模式)

上面借用的构造函数模式的最后一个改进版本仍然有问题。它将父类的原型直接分配给子类的原型,这将导致一个问题。如果子类的原型被修改,修改也会影响父类的原型,然后是父类对象,这绝对不是大家想看到的。为了解决这个问题,有一个临时构造函数模式。

var Parent=function(name){ this . name=name | | ' Parent ';} ;parent . prototype . getname=function(){ return this . name;} ;parent . prototype . obj={ a : 1 };var Child=function(name){ parent . apply(this,arguments);} ;var F=新函数(){ };原型=父原型;child . prototype=new F();var parent=新父代(' my Parent ');var Child=new Child(' my Child ');console . log(parent . getname());//myparentconsole . log(child . getname());//myChild个人综合模式

《Javascript模式》,圣杯模式结束了,但是无论上面哪种方法都有一个不容易发现的问题。如您所见,我在“父对象”的原型属性中添加了一个obj对象文字属性,但它从未起作用。让我们在圣杯模型的基础上看看下面的情况:

var Parent=function(name){ this . name=name | | ' Parent ';} ;parent . prototype . getname=function(){ return this . name;} ;parent . prototype . obj={ a : 1 };var Child=function(name){ parent . apply(this,arguments);} ;var F=新函数(){ };原型=父原型;child . prototype=new F();var parent=新父代(' my Parent ');var Child=new Child(' my Child ');console . log(child . obj . a);//1 console . log(parent . obj . a);//1 child . obj . a=2;console . log(child . obj . a);//2 con sole . log(parent . obj . a);//2在上述情况下,当我修改子对象obj.a的同时,父类原型中的obj.a也会被修改,这就导致了和共享原型一样的问题。发生这种情况是因为当我们访问child.obj.a时,我们总是会沿着原型链找到父类的原型,然后找到obj属性,然后修改obj.a看看下面的情况:

var Parent=function(name){ this . name=name | | ' Parent ';} ;parent . prototype . getname=function(){ return this . name;} ;parent . prototype . obj={ a : 1 };var Child=function(name){ parent . apply(this,arguments);} ;var F=新函数(){ };原型=父原型;child . prototype=new F();var parent=新父代(' my Parent ');var Child=new Child(' my Child ');console . log(child . obj . a);//1 console . log(parent . obj . a);//1 child . obj . a=2;console . log(child . obj . a);//2 con sole . log(parent . obj . a);//2这里有一个关键问题。当对象访问原型中的属性时,原型中的属性是只读的,这意味着子对象可以读取obj对象,但不能修改原型中的obj对象引用。因此,当孩子修改obj时,不会影响原型中的obj。它只是向自己的对象添加了一个obj属性,覆盖了父原型中的obj属性。而当子对象修改obj.a时,它首先读取原型中obj的引用。此时child.obj和Parent.prototype.obj指向同一个对象,所以子对象对obj.a的修改会影响Parent.prototype.obj.a的值,进而影响父类的对象。AngularJS中$scope的嵌套继承是通过Javasript模型中的原型继承实现的。

根据上面的描述,只要子类对象中访问的原型和父原型是同一个对象,就会出现上面的情况,所以我们可以复制父原型,然后分配给子类原型,这样当子类修改原型中的属性时,只会修改父原型的一个副本,不会影响父原型。具体实现如下:

var deepClone=function(source,target){ source=source | | { };target=target | | { };var toStr=object . prototype . tostring,arrStr='[对象数组]';for(source中的var I){ if(source . HasownProperty(I)){ var item=source[I];if(type of item==' object '){ target[I]=(ToStr . apply(item))。toLowerCase()===arrStr)?[] : {} ;深度克隆(项目,目标[I]);} else { target[I]=item;} } }返回目标;} ;var Parent=function(name){ this . name=name | | ' Parent ';} ;parent . prototype . getname=function(){ return this . name;} ;parent . prototype . obj={ a : ' 1 ' };var Child=function(name){ parent . apply(this,arguments);} ;child . prototype=deep clone(parent . prototype);var Child=new Child(' Child ');var Parent=new Parent(' Parent ');console . log(child . obj . a);//1 console . log(parent . obj . a);//1 child . obj . a=' 2 ';console . log(child . obj . a);//2 con sole . log(parent . obj . a);//1基于以上所有考虑,Javascript继承的具体实现如下。这里只考虑子函数和父函数都是函数的情况:

var deepClone=function(source,target){ source=source | | { };target=target | | { };var toStr=对象。原型。tostring,arrStr='[对象数组]';用于(来源中的var I){ if(来源。hasown property(I)){ var item=source[I];if(项的类型==' object '){ target[I]=(ToStr。应用(项目)).toLowerCase()===arrStr)?[] : {} ;深度克隆(项目,目标[I]);} else { target[I]=item;} } }返回目标;} ;var expand=function(父,子){ Child=Child | | function(){ };如果(父===未定义)返回Child//借用父类构造函数child=function(){ parent。应用(这个,论点);} ;//通过深拷贝继承父类原型孩子。原型=深度克隆(父。原型);//重置构造器属性孩子。原型。构造函数=子;} ;更多关于Java脚本语言相关内容感兴趣的读者可查看本站专题: 《javascript面向对象入门教程》 、 《JavaScript错误与调试技巧总结》 、 《JavaScript数据结构与算法技巧总结》 、 《JavaScript遍历算法与技巧总结》 及《JavaScript数学运算用法总结》

希望本文所述对大家Java脚本语言程序设计有所帮助。

版权声明:详细说明JavaScript使用原型和原型链实现对象继承的方法是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。