摘要:這個構造函數的不管從調用方式還是內部寫法就都很有的感覺,但是從用途上來說,它其實更靠近的概念是中的工廠方法。到這里,所有關于繼承的東西講完了,接下來準備準備說說當中的封裝
所謂的對象,就是抽象化的數據本身一個面向對象轉向面向原型的困惑
我發現Javascript這門語言每次翻開都會帶給人新感受,尤其是看完其他語言的面向對象再來看它,但是如果你也是過來人就一定記得教科書里面冗長乏味的面向對象,所有的書上都會跟你這么說:面向對象是對要解決的問題的一種抽象,比如很經典的Java或者C++,class就是根基,然后類實例化出對象balabala....初學者來看的話其實是很難接受的,但是挺過這個時期,就會產生一種理所應當的感覺,就會覺得:面向對象當然需要類啦當然需要實例化啦,不然怎么繼承的之類的。當然基本上主流的面向對象語言都會提供基本相同的概念。但是有個異類就是JavaScript,如果你用其他語言的概念來理解這個世界里的對象可能會找不著北。因為這個世界里沒有“類”這個東西,所有的東西都是對象。
朝下看的時候,我建議學過面向對象的人忘掉“類”這個東西,不然很容易就會搞混。
那到底什么是對象呢?這個問題問淺了是個傻問題問深了又變成了一個哲學問題,每個語言甚至每個人都有不同的答案,但是如果你只有十天來設計一門語言的話,你肯定也是想把這個東西設計的越簡單越好,所以對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();
這樣一個對象就寫好了,不僅如此,我們在運行時還可以動態的修改內部對象的屬性,以及增加方法等等非常自由。第一眼看上去非常的直觀,但是仔細想想看,問題其實很多,比如,屬性這樣無限制的訪問一點安全性都沒有,再比如我想再要生成一個人但是名字叫小紅的,就很費勁,再再比如我怎么實現繼承?問題很多我們一個一個來說
純對象怎么完成繼承?其實繼承說白了,要做的事情就是把兩個毫不相干的人建立父子關系,但是怎么建立呢?Javascript語言的對象生來都有一個特殊屬性叫__proto__,我們可以用這個屬性來關聯其他對象,就像這樣:
var Teacher={ //這里添加老師的屬性和方法 __proto__:Person } Teacher.eat();
這樣,兩個對象之間就建立了聯系,人類(對象)是老師(對象)的原型,用圖表示就是:
這樣一條鏈條把對象之間聯系起來,這樣使用Teacher調用eat方法的時候找不到就順著鏈子朝上找一直找到頭如果沒有就報錯,看起來很完美。
怎么欺騙其他世界的程序員?但是大家都知道高級語言都是要吸引別人來用的,這個方式實在是和其他語言不太一樣,怎么吸引其他人來用呢?本著不行就封裝一層的原則于是語言提供了構造函數,但是這個構造函數到這里為止還是和其他語言有完全不同的意義(當然使用上區別不大)。
function Person(){ this.name=name; this.eat=function(){ console.log(this.name+" eat food now"); } } ming =new Student("xiaoming"); hong =new Student("xiaohong");
這個構造函數的不管從調用方式還是內部寫法就都很有Java Class的感覺,但是從用途上來說,它其實更靠近的概念是Java中的工廠方法。而且使用的時候還使用了new這個關鍵字,同時解決了上面的那個不用生成一個對象就寫一大串代碼的尷尬。同時還很靈活,你還是可以在ming或者hong這個對象上動態添加方法。
但是上面的操作有個很操蛋的問題就是,因為這個語言沒有類只有對象,所以你構造函數里寫的方法會原封不動的出現在新生成的對象當中,這意味著每個新生成的對象都有相同的函數,這就很浪費而且對象多了還吃內存。設計者當然也想到了這個問題,他用純對象的思考方式想了一個解決辦法,舉個例子:
現在有一個Person構造函數(上面那樣的),通常使用它來生成新的對象(小紅小明等等)來通過原型鏈來訪問父對象的方法,基于這個模型那我索性就再生成一個對象掛在Person下面,用一個屬性指向它(大家都知道我說的就是prototype這個屬性啦),公共的方法完全可以都放在這個對象里面,但是怎么調用這些方法呢?其實大家既然都是對象,小明小紅的__proto__里面寫的只要是Person.prototype就完事了呀,說了這么多用一個圖來標識一下:
對我們來說只需要關注橫著一排的原型鏈就行了,至于Person構造函數是一個函數自然也是一個對象(函數也是對象),同樣自然有自己的原型鏈但是這里和主體無關就不體現在圖上了。
如果原型鏈的知識都差不多了的話我覺得就可以放出下面這張廣為人知的圖來記憶一番了:
然后寫了這么多,你就發現其實繼承在Javascript當中原來也是一個謊言--只要把新的對象掛上原型鏈就算是“繼承”了。那問題就變成了怎么構建原型鏈,我們還是放上道爺發明的一種方式來實現繼承(方法多種多樣,我覺得道爺的這種橋接并且不污染上下文環境的方式相當好用)
//父類 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; } //使用一個空構造函數來橋接 function F(){} F.prototype=Student.prototype; //把原本指向Function.prototype的指針指向父類 PrimaryStudent.prototype=new F();//橋接子類對象到一個F的匿名對象上 PrimaryStudent.prototype.constructor=PrimaryStudent;//糾正構造函數指向 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!關系就是這么橋接好的,我們如果再在外面包一層函數就完全可以做工具函數來用
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味道十足,但是別忘了,其實語言的內部仍然是原型鏈。
到這里,所有關于繼承的東西講完了,接下來準備準備說說Javascript當中的封裝
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/89975.html
摘要:個人前端文章整理從最開始萌生寫文章的想法,到著手開始寫,再到現在已經一年的時間了,由于工作比較忙,更新緩慢,后面還是會繼更新,現將已經寫好的文章整理一個目錄,方便更多的小伙伴去學習。 showImg(https://segmentfault.com/img/remote/1460000017490740?w=1920&h=1080); 個人前端文章整理 從最開始萌生寫文章的想法,到著手...
摘要:上下文切換上下文最直觀的表現就是代碼塊中的,通常在面向對象的編程中用到,來指代當前類生成的對應實例,與其他語言的一致。咦,是干嘛的,有沒有其他方式實現,請自行谷歌。 分享第一篇,關于 NodeJS —— Javascript 的常用知識以及如何從 Javascript 開發者過渡到 NodeJS 開發者(不會介紹具體的框架)。在讀本文前,希望你對 javascript 有一些初步的認識...
摘要:入門,第一個這是一門很新的語言,年前后正式公布,算起來是比較年輕的編程語言了,更重要的是它是面向程序員的函數式編程語言,它的代碼運行在之上。它通過編輯類工具,帶來了先進的編輯體驗,增強了語言服務。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不覺已經到來了,總結過去的 2017,相信小伙們一定有很多收獲...
摘要:入門,第一個這是一門很新的語言,年前后正式公布,算起來是比較年輕的編程語言了,更重要的是它是面向程序員的函數式編程語言,它的代碼運行在之上。它通過編輯類工具,帶來了先進的編輯體驗,增強了語言服務。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不覺已經到來了,總結過去的 2017,相信小伙們一定有很多收獲...
閱讀 1002·2023-04-25 19:35
閱讀 2660·2021-11-22 09:34
閱讀 3690·2021-10-09 09:44
閱讀 1723·2021-09-22 15:25
閱讀 2939·2019-08-29 14:00
閱讀 3374·2019-08-29 11:01
閱讀 2598·2019-08-26 13:26
閱讀 1740·2019-08-23 18:08