浅谈JavaScript的面向对象和它的封装、继承、多态_第1页
浅谈JavaScript的面向对象和它的封装、继承、多态_第2页
浅谈JavaScript的面向对象和它的封装、继承、多态_第3页
浅谈JavaScript的面向对象和它的封装、继承、多态_第4页
浅谈JavaScript的面向对象和它的封装、继承、多态_第5页
已阅读5页,还剩10页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

写在前面既然是浅谈,就不会从原理上深度分析,只是帮助我们更好地理解…面向对象与面向过程面向对象和面向过程是两种不同的编程思想,刚开始接触编程的时候,我们大都是从面向过程起步的,毕竟像我一样,大家接触的第一门计算机语言大概率都是C语言,C语言就是一门典型的面向过程的计算机语言。面向过程主要是以动词为主,解决问题的方式是按照顺序一步一步调用不同的函数。面向对象是以名词为主,将问题抽象出具体的对象,而这个对象有自己的属性和方法,在解决问题的时候,是将不同的对象组合在一起使用。//面向过程装大象,开(冰箱)2.(大象)装进(冰箱)3.关(冰箱)//面向对象装大象工.冰箱.开门()2.冰箱.装进(大象)3.冰箱.关门()从这个例子可以看出,面向对象是以主谓为主,将主谓堪称一个一个的对象,然后对象有自己的属性和方法。面向对象是以功能来划分问题的,而不是步骤。功能上的统一保证了面向对象设计的可扩展性,解决了代码重用性的问题。这也是在漫长的程序设计的发展过程中得到的验证结果,面向对象的编程思想较之于面向过程较好一点封装面向对象有封装、继承和多态三大特性。封装:就是把事物封装成类,隐藏事物的属性和方法的实现细节,仅对外公开接I-IO在ES5中,并没有dass的概念,但是由于js的函数级作用域(函数内部的变量函数外访问不到)。所以我们可以模拟class。在es5中,类其实就是保存了一个函数的变量,这个函数有自己的属性和方法。将属性和方法组成一个类的过程就是封装。.通过构造函数添加JavaScript提供了一个构造函数(Constructor)模式,用来在创建对象时初始化对象。构造函数其实就是普通的函数,只不过有以下的特点①首字母大写(建议构造函数首字母大写,即使用大驼峰命名,非构造函数首字母小写)②内部使用this③使用new生成实例通过构造函数添加属性和方法实际上也就是通过this添加的属性和方法。因为this总是指向当前对象的,所以通过this添加的属性和方法只在当前对象上添加,是该对象自身拥有的。所以我们实例化一个新对象的时候,this指向的属性和方法都会得到相应的创建,也就是会在内存中复制一份,这样就造成了内存的浪费。functionCcit(iaa^e,color){this.color=color;this.eat=(0=>{c。八so【e.log("fish!")}))〃生成实例vavcatl=newCcit^to^","g^y")通过this定义的属性和方法,我们实例化对象的时候斗湖重新复制一份.通过原型prototype封装在类上通过this的方式添加属性和方法会导致内存浪费的现象,有什么办法可以让实例化的类所使用的属性和方法直接使用指针指向同一个属性和方法。这就是原型的方法JavaScript规定,每一个构造函数都有一个prototype属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。也就是说,对于那些不变的属性和方法,我们可以直接将其添加在类的pmWtgpe对象上。functionCat(iaa^v\efcolor){this.nawe=八〃mc;this.color=color)}Ctotype.type="英短";Ctotype,eat=(()=>{alert(nfisk!")!)//生成实例varcatl=newCat^Tow^f'gray');varcatZ=newCat^Kobe^'purple1);con$ole.log(catl.type);〃英短cat2.eat();//fish!这时所有实例的type属性和eat()方法,其实都是同一个内存地址,指向prototype对象,因此就提高了运行效率。但是这样做也有弊端,因为实例化的对象的原型都是指向同一内存地址,改动其中一个对象的属性可能会影响到其他的对象es6中的类和封装es6声明一个类①构造器:构造器内创建自有属性②方法:声明类实例具有的方法classCat{〃等价于Cat构造器constructor(na^v\e){1〃更加简单的声明类的内部函数〃等价于Ctotype.eat血0(console.tog("fish!");}]//4.成实例varcatt=newCat(uto^");catl.eatO;//fish!coi^sole.(og(catXiiastaMeofCat);//trueco^ole.(og(catli^tanceofObject);//trueconsole.log(typeofCat);//fuMtioiacoiaso(e.log(typeofCtotype.eat);//fuaction从上面class声明的Cat为例:Cat类是一个具有构造函数行为的函数,其中内部方法eat实际上就是Ctotype.eatO所以说es6的class封装类,本质上是es5实现方式的语法糖最主要的区别在于,class类的属性是不可重新赋值和不可枚举的,Catprototype就是一个只读属性class和自定义类型的区别class的声明不会提升,与let类似class的声明自动运行于严格模式之下class声明的方法不可枚举class的内部方法没有constructor属性,无法new(5)调用class的构造函数必须new(6)class内部方法不能同名class类的使用class作为js中的一级公民,可以被当作值来直接使用〃工.类—U数传入函数functioncreateObj(ClassNai^e){returnnewClassNakv\e()}〃2.M即执行,实现单例模式letcat•工=newcla双constructor(八〃Me){)MtQ{c。八sole.log(”fish!")}K〃t。")catl.eatO//fish!继承继承就是子类可以使用父类的所有功能,并且对这些功能进行扩展。继承的过程,就是从一般到特殊的过程。1.类式继承所谓的类式继承就是使用的原型的方式,将方法添加在父类的原型上,然后子类的原型是父类的一个实例化对象。〃声明父类varSuperclass=functioia(){letid=1;以us.八〃kwe=tkissuperValue=fuMtioia(){conso(e.log('tkisissuperValue!1)}}//为父类添加共行方法SupefClass.pYototgpe.getSupeNalue=function。(returnthi^superValue(););〃声明子类vaHSubClass=fuMtio^O{thissubValue=(()=>{c。八sole.logCthisissuhValue!1))))〃继承父类SubCtotype=newSuperCSssO;//为广类添加J*、仃力法S〃Sa〃ss.pK。切tgpe.getSubMH”。=fuMtioi^O{returntkissubValiAC()}〃生成实例varsubt=newSubClass();varsubz-newSubCSss。;siAbl.getSuperValueO;//thisissuperValue!subl.getSubValueO;//thisissubValue1.co八so/eJog(subl.id);//uiadefiMdco^oledog(subl.Mi^.e);//^'java"]subl.八akne.p"次"WW);C0nso/e」og(subt.n〃Fv\e);//["java","pkp"]console.log(sbib2..i^ai^e);//["java1^"php"]其中最核心的是SubCtotype=newSuperClassO;类的原型对象prototype对象的作用就是为类的原型添加共有的方法的,但是类不能直接访问这些方法,只有将类实例化之后,新创建的对象复制了父类构造函数的属性和方法,并将原型proto指向了父类的原型对象。这样子类就可以访问父类的属性和方法,同时,父类中定义的属性和方法不会被子类继承。but使用类继承的方法,如果父类的构造函数中有引用数据类型,就会在子类中被所有实例共用,因此一个子类的实例如果更改了这个引用数据类型,就会影响到其他子类的实例。构造函数继承为了克服类继承的缺点,才有了构造函数继承,构造函数继承的核心思想就是SuperClass.call(thisfid),直接改变this的指向,使通过this创建的属性和方法在子类中复制一份,因为是单独复制的,所以各个实例化的子类互不影响。but会造成内存浪费的问题〃构造函数继承//声明父类vavSuperCla^=fuiactioia(id){varnakvxe='java'this.languages=['java'j'php'j^uby1];tkis.id=id]//浦明广类varSubclass=fuMtio^(id){SiAperClass.cal^tkiijid)1//生成实例varsub工=newSubCla^(^);vars〃b2=newSubClas^X);conso(e.log(sub2..id);//2c。八so/e・/og(sub:t.nakvve);//以八defined^ubl.languages.pu$h("pytkoia");co^ole.log($ubl.laiaguage$);//[JaR,”p-nx匆)'pytho^jco^ole.log^ubz.laiaguag&s);//['java^'php','ruby1]组合式继承组合式继承是汲取了两者的优点,既避免了内存浪费,又使得每个实例化的子类互不影响。//组合式继承//声明父类varSuperClass=fuMtio^.(iaai^e){this.languages=[^ava'j'php^^uby1];〃声明父类原型方法SuperCtotyp&skov^La^gs=facetion0(console.log(thi^.languages);}〃声明子类varSubClass=function(nakvie){SuperCSss.cHgu's,八〃mc))//子类继承父类(链式继承)SubCtotype=newSuperclass。;〃生成实例var=newSubClassCpytko^1);varsubz=newSubClassCgo1);suS2.s〃owLMgs();//['java1j'php'j'ruby1]$ubl.languages.pusk($b(bl.iaakv\e);console.log($(Abl.language$);//[,,jav,auj"php1^''ruby11,"python"]console.log(sub2.Janguages);//[,ja^a,J^uby1]but警告:组合式继承方法固然好,但是会导致一个问题,父类的构造函数会被创建两次(call。的时候一遍,new的时候又一遍)寄生组合继承组合式继承的缺点的关键是父类的构造函数在类继承和构造函数继承的组合形式被创建了两边,但是在类继承中我们并不需要创建父类的构造函数,我们只要子类继承父类的原型即可。所以我们先给父类的原型创建一个副本,然后修改子类的constructor属性,最后在设置子类的原型就可以了//原型式继承//原型式继承其实就是类式继承的封装,实现的功能返回一个实例,该实例的原型继承了传入的。对象functionii^kentObject(o){〃声明一个过渡函数FunctionF0(}〃过渡对象的原型链继承父对象F.prototype=o;〃返回一个过渡对象的实例,该实例的原型继承了父对象returnnewF();}〃寄生式继承//寄生式继承就是对原型继承的第二次封装,使得子类的原型等于父类的原型。并且在第二次封装的过程中对继承的对象进行了扩展functioni^.hentPrototype(subCla^,superclass)[〃复制一份父类的原型保存在变量中,使得p的原型等于父类的原型varp=i^hentObject(superCla^.prototype);〃修正因为重写子类原型导致子类contractor属性被修改^.constructor=subClass;〃设置子类的原型subCtotype=p;)//定义父英varSuperClass=fimc由'。八(八〃Me){this.nai^e=nakv\e;tkis.languages=["java1^"pkp11,"pythoia"]1//定义父类原型方法SuperCtotypesho\A/L-a^gs=funct/on(){cok\sole.log(this.language$);}〃定义广类varSubClass=Fuiacti。八(八a3e){Supcrag.ca"(协is…3e)}iiahentPrototypeCSubClass,Superclass);vavsufel=newSubCla^Cgo1);es6中的继承classSuperclass{co^tractor(v^akne){物is.八〃kv1e=八〃~this.languages=[Java,WJgo);)showLangsO(co八so(e.【og(thi,.(angaages);]}classSubClassextendsSuperclass{c0八struct。r(八〃me){super(八〃Me))〃重写父类中的方法showUmgsO(tkis.la^guages.pusk(tkis.iaai^e)console.Iog(this.la八guages);}}//生成实例varsub=newS”bCSss1韩二虎,);co^sole.log(^ub.yxai^e);〃韩.虎sub.showL〃八gs();//fjava","pkp","go"」"帏二虎"]多态多态实际上是不同对象作用与同一操作产生不同的效果。多态的思想实际上是把“想做什么"和"谁去做"分开。多态的好处在于,你不必再向对象询问“你是什么类型”后根据得到的答案再去调用对象的某个行为。你尽管去调用这个行为就是了,其他的一切可以由多态来负责。规范来说,多态最根本的作用就是通过吧过程化的条件语句转化为对象的多态性,从而消除这些条件分支语句。由于JavaScript中提到的关于多态的详细介绍并不多,这里简单的通过一个例子来介绍就好//非多态 varhobby=Fu八ctY。八(〃八演曲《if(anikv\al==匕。外{cat.eatOif(aniMal=='dog'){dog.eat()}]varcat-{eat:fuMtioiaQ(]}vavdog-{eat:fuMtioi^O{c。八so/e」og(123);hobbyCcat1);//fish!ho

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论