日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
淺談JavaScript的面向?qū)ο蠛退姆庋b、繼承、多態(tài)

寫在前面

創(chuàng)新互聯(lián)建站"三網(wǎng)合一"的企業(yè)建站思路。企業(yè)可建設(shè)擁有電腦版、微信版、手機(jī)版的企業(yè)網(wǎng)站。實(shí)現(xiàn)跨屏營(yíng)銷,產(chǎn)品發(fā)布一步更新,電腦網(wǎng)絡(luò)+移動(dòng)網(wǎng)絡(luò)一網(wǎng)打盡,滿足企業(yè)的營(yíng)銷需求!創(chuàng)新互聯(lián)建站具備承接各種類型的成都網(wǎng)站設(shè)計(jì)、做網(wǎng)站、成都外貿(mào)網(wǎng)站建設(shè)公司項(xiàng)目的能力。經(jīng)過(guò)十載的努力的開拓,為不同行業(yè)的企事業(yè)單位提供了優(yōu)質(zhì)的服務(wù),并獲得了客戶的一致好評(píng)。

既然是淺談,就不會(huì)從原理上深度分析,只是幫助我們更好地理解...

面向?qū)ο笈c面向過(guò)程

面向?qū)ο蠛兔嫦蜻^(guò)程是兩種不同的編程思想,剛開始接觸編程的時(shí)候,我們大都是從面向過(guò)程起步的,畢竟像我一樣,大家接觸的***門計(jì)算機(jī)語(yǔ)言大概率都是C語(yǔ)言,C語(yǔ)言就是一門典型的面向過(guò)程的計(jì)算機(jī)語(yǔ)言。

面向過(guò)程主要是以動(dòng)詞為主,解決問(wèn)題的方式是按照順序一步一步調(diào)用不同的函數(shù)。

面向?qū)ο笫且悦~為主,將問(wèn)題抽象出具體的對(duì)象,而這個(gè)對(duì)象有自己的屬性和方法,在解決問(wèn)題的時(shí)候,是將不同的對(duì)象組合在一起使用。

 
 
 
  1. //面向過(guò)程裝大象  
  2. 1.開(冰箱)  
  3. 2.(大象)裝進(jìn)(冰箱)  
  4. 3.關(guān)(冰箱)  
 
 
 
  1. //面向?qū)ο笱b大象  
  2. 1. 冰箱.開門()  
  3. 2. 冰箱.裝進(jìn)(大象)  
  4. 3. 冰箱.關(guān)門() 

從這個(gè)例子可以看出,面向?qū)ο笫且灾髦^為主,將主謂堪稱一個(gè)一個(gè)的對(duì)象,然后對(duì)象有自己的屬性和方法。

面向?qū)ο笫且怨δ軄?lái)劃分問(wèn)題的,而不是步驟。功能上的統(tǒng)一保證了面向?qū)ο笤O(shè)計(jì)的可擴(kuò)展性,解決了代碼重用性的問(wèn)題。

這也是在漫長(zhǎng)的程序設(shè)計(jì)的發(fā)展過(guò)程中得到的驗(yàn)證結(jié)果,面向?qū)ο蟮木幊趟枷胼^之于面向過(guò)程較好一點(diǎn)

封裝

面向?qū)ο笥蟹庋b、繼承和多態(tài)三大特性。

封裝:就是把事物封裝成類,隱藏事物的屬性和方法的實(shí)現(xiàn)細(xì)節(jié),僅對(duì)外公開接口。

在ES5中,并沒有class的概念,但是由于js的函數(shù)級(jí)作用域(函數(shù)內(nèi)部的變量函數(shù)外訪問(wèn)不到)。所以我們可以模擬class。在es5中,類其實(shí)就是保存了一個(gè)函數(shù)的變量,這個(gè)函數(shù)有自己的屬性和方法。將屬性和方法組成一個(gè)類的過(guò)程就是封裝。

1.通過(guò)構(gòu)造函數(shù)添加

JavaScript提供了一個(gè)構(gòu)造函數(shù)(Constructor)模式,用來(lái)在創(chuàng)建對(duì)象時(shí)初始化對(duì)象。構(gòu)造函數(shù)其實(shí)就是普通的函數(shù),只不過(guò)有以下的特點(diǎn)

 
 
 
  1. ①首字母大寫(建議構(gòu)造函數(shù)首字母大寫,即使用大駝峰命名,非構(gòu)造函數(shù)首字母小寫)  
  2. ②內(nèi)部使用this  
  3. ③使用new生成實(shí)例 

通過(guò)構(gòu)造函數(shù)添加屬性和方法實(shí)際上也就是通過(guò)this添加的屬性和方法。因?yàn)閠his總是指向當(dāng)前對(duì)象的,所以通過(guò)this添加的屬性和方法只在當(dāng)前對(duì)象上添加,是該對(duì)象自身?yè)碛械?。所以我們?shí)例化一個(gè)新對(duì)象的時(shí)候,this指向的屬性和方法都會(huì)得到相應(yīng)的創(chuàng)建,也就是會(huì)在內(nèi)存中復(fù)制一份,這樣就造成了內(nèi)存的浪費(fèi)。

 
 
 
  1. function Cat(name,color){  
  2.     this.name = name;  
  3.     this.color = color;  
  4.     this.eat = (() => {  
  5.         console.log("fish!")  
  6.     })  
  7. }  
  8. //生成實(shí)例  
  9. var cat1 = new Cat("tom", "gray") 

通過(guò)this定義的屬性和方法,我們實(shí)例化對(duì)象的時(shí)候斗湖重新復(fù)制一份

2.通過(guò)原型prototype封裝

在類上通過(guò)this的方式添加屬性和方法會(huì)導(dǎo)致內(nèi)存浪費(fèi)的現(xiàn)象,有什么辦法可以讓實(shí)例化的類所使用的屬性和方法 直接使用指針 指向同一個(gè)屬性和方法。

這就是原型的方法

 
 
 
  1. JavaScript規(guī)定,每一個(gè)構(gòu)造函數(shù)都有一個(gè)prototype屬性,指向另一個(gè)對(duì)象。這個(gè)對(duì)象的所有屬性和方法,都會(huì)被構(gòu)造函數(shù)的實(shí)例繼承。  
  2. 也就是說(shuō),對(duì)于那些不變的屬性和方法,我們可以直接將其添加在類的prototype對(duì)象上。  
 
 
 
  1. function Cat(name,color){  
  2.             this.name = name;  
  3.             this.color = color;  
  4.         }  
  5.         Cat.prototype.type = "英短";  
  6.         Cat.prototype.eat = ( () => {  
  7.             alert("fish!")  
  8.         } )       
  9.  
  10.         //生成實(shí)例  
  11.         var cat1 = new Cat('Tom', 'gray');  
  12.         var cat2 = new Cat('Kobe', 'purple');  
  13.         console.log(cat1.type); //英短  
  14.         cat2.eat(); //fish! 

這時(shí)所有實(shí)例的type屬性和eat()方法,其實(shí)都是同一個(gè)內(nèi)存地址,指向prototype對(duì)象,因此就提高了運(yùn)行效率。

但是這樣做也有弊端,因?yàn)閷?shí)例化的對(duì)象的原型都是指向同一內(nèi)存地址,改動(dòng)其中一個(gè)對(duì)象的屬性可能會(huì)影響到其他的對(duì)象

es6中的類和封裝

es6聲明一個(gè)類

①構(gòu)造器:構(gòu)造器內(nèi)創(chuàng)建自有屬性

②方法:聲明類實(shí)例具有的方法

 
 
 
  1. class Cat {  
  2.     //等價(jià)于Cat構(gòu)造器  
  3.     constructor(name) {  
  4.         this.name = name;  
  5.     }  
  6.     //更加簡(jiǎn)單的聲明類的內(nèi)部函數(shù)  
  7.     //等價(jià)于 Cat.prototype.eat  
  8.     eat() {  
  9.         console.log("fish!");  
  10.     }  
  11. }  
  12. //生成實(shí)例  
  13. var cat1 = new Cat("tom");  
  14. cat1.eat(); //fish!  
  15. console.log(cat1 instanceof Cat); //true  
  16. console.log(cat1 instanceof Object); //true  
  17. console.log(typeof Cat); //function  
  18. console.log(typeof Cat.prototype.eat); //function 

從上面class聲明的Cat為例:Cat類是一個(gè)具有構(gòu)造函數(shù)行為的函數(shù),其中內(nèi)部方法eat實(shí)際上就是Cat.prototype.eat()

所以說(shuō)es6的class封裝類,本質(zhì)上是es5實(shí)現(xiàn)方式的語(yǔ)法糖

最主要的區(qū)別在于,class類的屬性是不可重新賦值和不可枚舉的,Cat.prototype就是一個(gè)只讀屬性

class和自定義類型的區(qū)別

(1)class的聲明不會(huì)提升,與let類似

(2)class的聲明自動(dòng)運(yùn)行于嚴(yán)格模式之下

(3)class聲明的方法不可枚舉

(4)class的內(nèi)部方法沒有 constructor 屬性,無(wú)法new

(5)調(diào)用class的構(gòu)造函數(shù)必須new

(6)class內(nèi)部方法不能同名

class類的使用

class作為js中的一級(jí)公民,可以被當(dāng)作值來(lái)直接使用

 
 
 
  1. //1.類名作為參數(shù)傳入函數(shù)  
  2. function createObj (ClassName) {  
  3.     return new ClassName()  
  4. }  
  5. //2.立即執(zhí)行,實(shí)現(xiàn)單例模式  
  6. let cat1 = new class{  
  7.     constructor (name) {  
  8.         this.name = name  
  9.     }  
  10.     eat() {  
  11.         console.log("fish!")  
  12.     }  
  13. }("tom”)  
  14. cat1.eat() //fish! 

繼承

繼承就是子類可以使用父類的所有功能,并且對(duì)這些功能進(jìn)行擴(kuò)展。繼承的過(guò)程,就是從一般到特殊的過(guò)程。

1.類式繼承

所謂的類式繼承就是使用的原型的方式,將方法添加在父類的原型上,然后子類的原型是父類的一個(gè)實(shí)例化對(duì)象。

 
 
 
  1. //聲明父類  
  2. var SuperClass = function(){  
  3.     let id = 1;  
  4.     this.name = ['java'];  
  5.     this.superValue = function() {  
  6.         console.log('this is superValue!')  
  7.     } 
  8. }  
  9. //為父類添加共有方法  
  10. SuperClass.prototype.getSuperValue = function () {  
  11.     return this.superValue();  
  12. };  
  13. //聲明子類  
  14. var SubClass = function() {  
  15.     this.subValue = (() => {  
  16.         console.log('this is subValue!')  
  17.     })  
  18. }  
  19. //繼承父類  
  20. SubClass.prototype = new SuperClass();  
  21. //為子類添加共有方法  
  22. SubClass.prototype.getSubValue = function() {  
  23.     return this.subValue()  
  24. }  
  25. //生成實(shí)例  
  26. var sub1 = new SubClass();  
  27. var sub2 = new SubClass();  
  28. sub1.getSuperValue(); //this is superValue!  
  29. sub1.getSubValue(); //this is subValue!  
  30. console.log(sub1.id); //undefined  
  31. console.log(sub1.name); //["java"]  
  32. sub1.name.push("php");   
  33. console.log(sub1.name); //["java", "php"]  
  34. console.log(sub2.name); //["java", "php"] 

其中最核心的是SubClass.prototype = new SuperClass();

類的原型對(duì)象prototype對(duì)象的作用就是為類的原型添加共有的方法的,但是類不能直接訪問(wèn)這些方法,只有將類實(shí)例化之后,新創(chuàng)建的對(duì)象復(fù)制了父類構(gòu)造函數(shù)的屬性和方法,并將原型 proto 指向了父類的原型對(duì)象。這樣子類就可以訪問(wèn)父類的屬性和方法,同時(shí),父類中定義的屬性和方法不會(huì)被子類繼承。

but使用類繼承的方法,如果父類的構(gòu)造函數(shù)中有引用數(shù)據(jù)類型,就會(huì)在子類中被所有實(shí)例共用,因此一個(gè)子類的實(shí)例如果更改了這個(gè)引用數(shù)據(jù)類型,就會(huì)影響到其他子類的實(shí)例。

構(gòu)造函數(shù)繼承

為了克服類繼承的缺點(diǎn),才有了構(gòu)造函數(shù)繼承,構(gòu)造函數(shù)繼承的核心思想就是SuperClass.call(this, id),直接改變this的指向,使通過(guò)this創(chuàng)建的屬性和方法在子類中復(fù)制一份,因?yàn)槭菃为?dú)復(fù)制的,所以各個(gè)實(shí)例化的子類互不影響。but會(huì)造成內(nèi)存浪費(fèi)的問(wèn)題

 
 
 
  1. //構(gòu)造函數(shù)繼承  
  2. //聲明父類  
  3. var SuperClass = function(id){  
  4.     var name = 'java'  
  5.     this.languages = ['java', 'php', 'ruby'];  
  6.     this.id = id   
  7. }  
  8. //聲明子類  
  9. var SubClass = function(id){  
  10.     SuperClass.call(this, id)  
  11. }  
  12. //生成實(shí)例  
  13. var sub1 = new SubClass(1);  
  14. var sub2 = new SubClass(2);  
  15. console.log(sub2.id); // 2  
  16. console.log(sub1.name); //undefined  
  17. sub1.languages.push("python");  
  18. console.log(sub1.languages); // ['java', 'php', 'ruby', 'python']  
  19. console.log(sub2.languages); // ['java', 'php', 'ruby'] 

組合式繼承

組合式繼承是汲取了兩者的優(yōu)點(diǎn),既避免了內(nèi)存浪費(fèi),又使得每個(gè)實(shí)例化的子類互不影響。

 
 
 
  1. //組合式繼承  
  2. //聲明父類  
  3. var SuperClass = function(name){  
  4.     this.languages = ['java', 'php', 'ruby'];  
  5.     this.name = name;  
  6. }  
  7.  //聲明父類原型方法  
  8. SuperClass.prototype.showLangs = function () {  
  9.     console.log(this.languages);  
  10. }  
  11. //聲明子類  
  12. var SubClass = function(name){  
  13.     SuperClass.call(this, name)  
  14. }  
  15. //子類繼承父類(鏈?zhǔn)嚼^承)  
  16. SubClass.prototype = new SuperClass();  
  17. //生成實(shí)例  
  18. var sub1 = new SubClass('python');  
  19. var sub2 = new SubClass('go');  
  20. sub2.showLangs(); //['java', 'php', 'ruby']  
  21. sub1.languages.push(sub1.name);  
  22. console.log(sub1.languages);//["java", "php", "ruby", "python"]  
  23. console.log(sub2.languages);//['java', 'php', 'ruby'] 

but警告:組合式繼承方法固然好,但是會(huì)導(dǎo)致一個(gè)問(wèn)題,父類的構(gòu)造函數(shù)會(huì)被創(chuàng)建兩次(call()的時(shí)候一遍,new的時(shí)候又一遍)

寄生組合繼承

組合式繼承的缺點(diǎn)的關(guān)鍵是 父類的構(gòu)造函數(shù)在類繼承和構(gòu)造函數(shù)繼承的組合形式被創(chuàng)建了兩邊,但是在類繼承中我們并不需要?jiǎng)?chuàng)建父類的構(gòu)造函數(shù),我們只要子類繼承父類的原型即可。

所以我們先給父類的原型創(chuàng)建一個(gè)副本,然后修改子類的 constructor 屬性,***在設(shè)置子類的原型就可以了

 
 
 
  1. //原型式繼承  
  2. //原型式繼承其實(shí)就是類式繼承的封裝,實(shí)現(xiàn)的功能返回一個(gè)實(shí)例,該實(shí)例的原型繼承了傳入的o對(duì)象  
  3. function inheritObject(o) {  
  4.     //聲明一個(gè)過(guò)渡函數(shù)  
  5.     function F() {}  
  6.     //過(guò)渡對(duì)象的原型鏈繼承父對(duì)象  
  7.     F.prototype = o;  
  8.     //返回一個(gè)過(guò)渡對(duì)象的實(shí)例,該實(shí)例的原型繼承了父對(duì)象  
  9.     return new F();  
  10. }  
  11. //寄生式繼承  
  12. //寄生式繼承就是對(duì)原型繼承的第二次封裝,使得子類的原型等于父類的原型。并且在第二次封裝的過(guò)程中對(duì)繼承的對(duì)象進(jìn)行了擴(kuò)展  
  13. function inheritPrototype(subClass, superClass){  
  14.     //復(fù)制一份父類的原型保存在變量中,使得p的原型等于父類的原型  
  15.     var p = inheritObject(superClass.prototype);  
  16.     //修正因?yàn)橹貙懽宇愒蛯?dǎo)致子類constructor屬性被修改  
  17.     p.constructor = subClass;  
  18.     //設(shè)置子類的原型  
  19.     subClass.prototype = p;  
  20. }  
  21. //定義父類  
  22. var SuperClass = function(name) {  
  23.     this.name = name;  
  24.     this.languages = ["java", "php", "python"]  
  25. }  
  26. //定義父類原型方法  
  27. SuperClass.prototype.showLangs = function() {  
  28.     console.log(this.languages);  
  29. }  
  30. //定義子類  
  31. var SubClass = function(name) {  
  32.     SuperClass.call(this,name)  
  33. }  
  34. inheritPrototype(SubClass, SuperClass);  
  35. var sub1 = new SubClass('go'); 

es6中的繼承

 
 
 
  1. class SuperClass {  
  2.     constructor(name) {  
  3.         this.name = name  
  4.         this.languages = ['java', 'php', 'go'];   
  5.     }  
  6.     showLangs() {  
  7.         console.log(this.languages);  
  8.     }  
  9. }  
  10. class SubClass extends SuperClass {  
  11.     constructor(name) {  
  12.         super(name)  
  13.     }  
  14.     //重寫父類中的方法  
  15.     showLangs() {  
  16.         this.languages.push(this.name)  
  17.         console.log(this.languages);  
  18.     }  
  19. }  
  20. //生成實(shí)例  
  21. var sub = new SubClass('韓二虎');  
  22. console.log(sub.name); //韓二虎  
  23. sub.showLangs(); //["java", "php", "go", "韓二虎"] 

多態(tài)

多態(tài)實(shí)際上是不同對(duì)象作用與同一操作產(chǎn)生不同的效果。多態(tài)的思想實(shí)際上是把 “想做什么” 和 “誰(shuí)去做” 分開。

多態(tài)的好處在于,你不必再向?qū)ο笤儐?wèn)“你是什么類型”后根據(jù)得到的答案再去調(diào)用對(duì)象的某個(gè)行為。你盡管去調(diào)用這個(gè)行為就是了,其他的一切可以由多態(tài)來(lái)負(fù)責(zé)。規(guī)范來(lái)說(shuō),多態(tài)最根本的作用就是通過(guò)吧過(guò)程化的條件語(yǔ)句轉(zhuǎn)化為對(duì)象的多態(tài)性,從而消除這些條件分支語(yǔ)句。

由于JavaScript中提到的關(guān)于多態(tài)的詳細(xì)介紹并不多,這里簡(jiǎn)單的通過(guò)一個(gè)例子來(lái)介紹就好

 
 
 
  1. //非多態(tài)       
  2. var hobby = function(animal){  
  3.     if(animal == 'cat'){  
  4.         cat.eat()  
  5.     }else if(animal == 'dog'){  
  6.         dog.eat()  
  7.     }  
  8. }  
  9. var cat = {  
  10.     eat: function() {  
  11.         alert("fish!")  
  12.     }  
  13. }  
  14. var dog = {  
  15.     eat: function() {  
  16.         alert("meat!")  
  17.     }  
  18. }  
  19. console.log(123);  
  20. hobby('cat'); //fish!  
  21. hobby('dog'); //meat! 

從上面的例子能看到,雖然 hobby 函數(shù)目前保持了一定的彈性,但這種彈性很脆弱的,一旦需要替換或者增加成其他的animal,必須改動(dòng)hobby函數(shù),繼續(xù)往里面堆砌條件分支語(yǔ)句。我們把程序中相同的部分抽象出來(lái),那就是吃某個(gè)東西。然后再重新編程。

 
 
 
  1. //多態(tài)       
  2. var hobby = function(animal){  
  3.     if(animal.eat instanceof Function){  
  4.         animal.eat();  
  5.     }  
  6. }  
  7. var cat = {  
  8.     eat: function() {  
  9.         alert("fish!")  
  10.     }  
  11. }  
  12. var dog = {  
  13.     eat: function() {  
  14.         alert("meat!")  
  15.     } 

現(xiàn)在來(lái)看這段代碼中的多態(tài)性。當(dāng)我們向兩種 animal 發(fā)出 eat 的消息時(shí),會(huì)分別調(diào)用他們的 eat 方法,就會(huì)產(chǎn)生不同的執(zhí)行結(jié)果。對(duì)象的多態(tài)性提示我們,“做什么” 和 “怎么去做”是可以分開的,這樣代碼的彈性就增強(qiáng)了很多。即使以后增加了其他的animal,hobby函數(shù)仍舊不會(huì)做任何改變。

 
 
 
  1. //多態(tài)       
  2. var hobby = function(animal){  
  3.     if(animal.eat instanceof Function){  
  4.         animal.eat();  
  5.     }  
  6. }  
  7. var cat = {  
  8.     eat: function() {  
  9.         alert("fish!")  
  10.     }  
  11. }  
  12. var dog = {  
  13.     eat: function() {  
  14.         alert("meat!")  
  15.     }  
  16. }  
  17. var aoteman = {  
  18.     eat: function(){  
  19.         alert("lil-monster!")  
  20.     }  
  21. }  
  22. hobby(cat); //fish!  
  23. hobby(dog); //meat!  
  24. hobby(aoteman); //lil-monster! 

網(wǎng)站標(biāo)題:淺談JavaScript的面向?qū)ο蠛退姆庋b、繼承、多態(tài)
轉(zhuǎn)載來(lái)于:http://www.dlmjj.cn/article/djidhoe.html