摘要:這個構(gòu)造函數(shù)的不管從調(diào)用方式還是內(nèi)部寫法就都很有的感覺,但是從用途上來說,它其實更靠近的概念是中的工廠方法。到這里,所有關(guān)于繼承的東西講完了,接下來準備準備說說當中的封裝
所謂的對象,就是抽象化的數(shù)據(jù)本身一個面向?qū)ο筠D(zhuǎn)向面向原型的困惑
我發(fā)現(xiàn)Javascript這門語言每次翻開都會帶給人新感受,尤其是看完其他語言的面向?qū)ο笤賮砜此?,但是如果你也是過來人就一定記得教科書里面冗長乏味的面向?qū)ο螅械臅隙紩氵@么說:面向?qū)ο笫菍σ鉀Q的問題的一種抽象,比如很經(jīng)典的Java或者C++,class就是根基,然后類實例化出對象balabala....初學(xué)者來看的話其實是很難接受的,但是挺過這個時期,就會產(chǎn)生一種理所應(yīng)當?shù)母杏X,就會覺得:面向?qū)ο螽斎恍枰惱伯斎恍枰獙嵗?,不然怎么繼承的之類的。當然基本上主流的面向?qū)ο笳Z言都會提供基本相同的概念。但是有個異類就是JavaScript,如果你用其他語言的概念來理解這個世界里的對象可能會找不著北。因為這個世界里沒有“類”這個東西,所有的東西都是對象。
朝下看的時候,我建議學(xué)過面向?qū)ο蟮娜送簟邦悺边@個東西,不然很容易就會搞混。
那到底什么是對象呢?這個問題問淺了是個傻問題問深了又變成了一個哲學(xué)問題,每個語言甚至每個人都有不同的答案,但是如果你只有十天來設(shè)計一門語言的話,你肯定也是想把這個東西設(shè)計的越簡單越好,所以對JavaScript來說,對象就是屬性+方法,簡單來說就是這樣:
var Person={ name :"XXX", age:18, address:"YYY", gender:0, eat:function(){ console.log("食"); }, wear:function(){ console.log("衣"); }, live:function(){ console.log("住"); }, walk:function(){ console.log("行"); } } Person.eat();
這樣一個對象就寫好了,不僅如此,我們在運行時還可以動態(tài)的修改內(nèi)部對象的屬性,以及增加方法等等非常自由。第一眼看上去非常的直觀,但是仔細想想看,問題其實很多,比如,屬性這樣無限制的訪問一點安全性都沒有,再比如我想再要生成一個人但是名字叫小紅的,就很費勁,再再比如我怎么實現(xiàn)繼承?問題很多我們一個一個來說
純對象怎么完成繼承?其實繼承說白了,要做的事情就是把兩個毫不相干的人建立父子關(guān)系,但是怎么建立呢?Javascript語言的對象生來都有一個特殊屬性叫__proto__,我們可以用這個屬性來關(guān)聯(lián)其他對象,就像這樣:
var Teacher={ //這里添加老師的屬性和方法 __proto__:Person } Teacher.eat();
這樣,兩個對象之間就建立了聯(lián)系,人類(對象)是老師(對象)的原型,用圖表示就是:
這樣一條鏈條把對象之間聯(lián)系起來,這樣使用Teacher調(diào)用eat方法的時候找不到就順著鏈子朝上找一直找到頭如果沒有就報錯,看起來很完美。
怎么欺騙其他世界的程序員?但是大家都知道高級語言都是要吸引別人來用的,這個方式實在是和其他語言不太一樣,怎么吸引其他人來用呢?本著不行就封裝一層的原則于是語言提供了構(gòu)造函數(shù),但是這個構(gòu)造函數(shù)到這里為止還是和其他語言有完全不同的意義(當然使用上區(qū)別不大)。
function Person(){ this.name=name; this.eat=function(){ console.log(this.name+" eat food now"); } } ming =new Student("xiaoming"); hong =new Student("xiaohong");
這個構(gòu)造函數(shù)的不管從調(diào)用方式還是內(nèi)部寫法就都很有Java Class的感覺,但是從用途上來說,它其實更靠近的概念是Java中的工廠方法。而且使用的時候還使用了new這個關(guān)鍵字,同時解決了上面的那個不用生成一個對象就寫一大串代碼的尷尬。同時還很靈活,你還是可以在ming或者hong這個對象上動態(tài)添加方法。
但是上面的操作有個很操蛋的問題就是,因為這個語言沒有類只有對象,所以你構(gòu)造函數(shù)里寫的方法會原封不動的出現(xiàn)在新生成的對象當中,這意味著每個新生成的對象都有相同的函數(shù),這就很浪費而且對象多了還吃內(nèi)存。設(shè)計者當然也想到了這個問題,他用純對象的思考方式想了一個解決辦法,舉個例子:
現(xiàn)在有一個Person構(gòu)造函數(shù)(上面那樣的),通常使用它來生成新的對象(小紅小明等等)來通過原型鏈來訪問父對象的方法,基于這個模型那我索性就再生成一個對象掛在Person下面,用一個屬性指向它(大家都知道我說的就是prototype這個屬性啦),公共的方法完全可以都放在這個對象里面,但是怎么調(diào)用這些方法呢?其實大家既然都是對象,小明小紅的__proto__里面寫的只要是Person.prototype就完事了呀,說了這么多用一個圖來標識一下:
對我們來說只需要關(guān)注橫著一排的原型鏈就行了,至于Person構(gòu)造函數(shù)是一個函數(shù)自然也是一個對象(函數(shù)也是對象),同樣自然有自己的原型鏈但是這里和主體無關(guān)就不體現(xiàn)在圖上了。
如果原型鏈的知識都差不多了的話我覺得就可以放出下面這張廣為人知的圖來記憶一番了:
然后寫了這么多,你就發(fā)現(xiàn)其實繼承在Javascript當中原來也是一個謊言--只要把新的對象掛上原型鏈就算是“繼承”了。那問題就變成了怎么構(gòu)建原型鏈,我們還是放上道爺發(fā)明的一種方式來實現(xiàn)繼承(方法多種多樣,我覺得道爺?shù)倪@種橋接并且不污染上下文環(huán)境的方式相當好用)
//父類 function Student(props){ this.name=props.name||"unnamed"; } Student.prototype.hello=function(){ console.log("Hello, " + this.name + "!"); } //子類 function PrimaryStudent(props) { Student.call(this, props); this.grade = props.grade || 1; } //使用一個空構(gòu)造函數(shù)來橋接 function F(){} F.prototype=Student.prototype; //把原本指向Function.prototype的指針指向父類 PrimaryStudent.prototype=new F();//橋接子類對象到一個F的匿名對象上 PrimaryStudent.prototype.constructor=PrimaryStudent;//糾正構(gòu)造函數(shù)指向 PrimaryStudent.prototype.getGrade=function(){ return this.grade; } // 開始測試 var xiaoming=new PrimaryStudent({ name:"xiaoming", grade:2 }); console.log(xiaoming.__proto__===PrimaryStudent.prototype); console.log(xiaoming.__proto__.__proto__===Student.prototype); console.log(xiaoming instanceof PrimaryStudent); console.log(xiaoming instanceof Student);
使用一張圖展示上面的代碼做了什么:
done!關(guān)系就是這么橋接好的,我們?nèi)绻僭谕饷姘粚雍瘮?shù)就完全可以做工具函數(shù)來用
ES6標準下的語法糖很明顯,上面的這個做法很費勁,或者說,不直觀沒法吸引別人來用,所以ES6標準里加了一個很Java的語法糖,就像下面這么寫:
class Person { constructor(name){ this.name=name; } hello(){ console.log(`${this.name} say hello to you!`); } } class Teacher extends Person{ constructor(name,gender){ super(name); this.gender=gender; } myGender(){ console.log(`${this.name}"s gender is ${this.gender}`); } } var x=new Teacher("niuguangzhe","nan"); x.myGender();
可以說是Java味道十足,但是別忘了,其實語言的內(nèi)部仍然是原型鏈。
到這里,所有關(guān)于繼承的東西講完了,接下來準備準備說說Javascript當中的封裝
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/89975.html
摘要:個人前端文章整理從最開始萌生寫文章的想法,到著手開始寫,再到現(xiàn)在已經(jīng)一年的時間了,由于工作比較忙,更新緩慢,后面還是會繼更新,現(xiàn)將已經(jīng)寫好的文章整理一個目錄,方便更多的小伙伴去學(xué)習(xí)。 showImg(https://segmentfault.com/img/remote/1460000017490740?w=1920&h=1080); 個人前端文章整理 從最開始萌生寫文章的想法,到著手...
摘要:上下文切換上下文最直觀的表現(xiàn)就是代碼塊中的,通常在面向?qū)ο蟮木幊讨杏玫?,來指代當前類生成的對?yīng)實例,與其他語言的一致。咦,是干嘛的,有沒有其他方式實現(xiàn),請自行谷歌。 分享第一篇,關(guān)于 NodeJS —— Javascript 的常用知識以及如何從 Javascript 開發(fā)者過渡到 NodeJS 開發(fā)者(不會介紹具體的框架)。在讀本文前,希望你對 javascript 有一些初步的認識...
摘要:入門,第一個這是一門很新的語言,年前后正式公布,算起來是比較年輕的編程語言了,更重要的是它是面向程序員的函數(shù)式編程語言,它的代碼運行在之上。它通過編輯類工具,帶來了先進的編輯體驗,增強了語言服務(wù)。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不覺已經(jīng)到來了,總結(jié)過去的 2017,相信小伙們一定有很多收獲...
摘要:入門,第一個這是一門很新的語言,年前后正式公布,算起來是比較年輕的編程語言了,更重要的是它是面向程序員的函數(shù)式編程語言,它的代碼運行在之上。它通過編輯類工具,帶來了先進的編輯體驗,增強了語言服務(wù)。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不覺已經(jīng)到來了,總結(jié)過去的 2017,相信小伙們一定有很多收獲...
閱讀 1220·2023-04-25 19:35
閱讀 2956·2021-11-22 09:34
閱讀 3870·2021-10-09 09:44
閱讀 1802·2021-09-22 15:25
閱讀 2996·2019-08-29 14:00
閱讀 3443·2019-08-29 11:01
閱讀 2679·2019-08-26 13:26
閱讀 1804·2019-08-23 18:08