我在讀不少優秀的JavaScript源碼時候經常被它詭異的語法搞的精疲力盡,因此時不時的加固JavaScript基礎知識是十分有必要的,這些知識每次溫故或者你換個角度去思考都能收穫頗多,那麼如此深不可測的語言是怎麼誕生的呢?它的祖師爺在創造它的時候是基於什麼思考的呢?我想若是大夥知道了這段歷史,或許理解起JavaScript來就會感受跟輕鬆些跟愜意些,說不定不少人所以而想好好的學習它。人總有點八卦的小毛病,回顧下一件事情或一個東西的歷史,探尋他們歷史過程當中的種種有趣的細節,必定是件頗有意思的事情。
java
這位就是JavaScript的開山祖師爺:Bremdan Eich(布蘭登·艾奇),如今在Mozilla公司擔任CTO。(額頭好長啊,又寬,要是希特勒在世必定會說這是太標準的雅利安人)。程序員
JavaScript的誕生於瀏覽器的鼻祖網景公司(Netscape),大約是1994年左右,網景公司(Netscape)發佈了Navigator瀏覽器0.9版,這是一款很經典的瀏覽器,網景公司(Netscape)的用戶數所以而出現了井噴的態勢,可是Navigator0.9不具有和訪問者互動的能力,在那個上網速度比蝸牛還慢的時代,網景公司(Netscape)急需一種腳本語言,使得瀏覽器和網頁進行交互,從而提高用戶的體驗。ajax
針對這個問題,網景公司(Netscape)有兩種選擇,一是採用現有的腳本語言,二是本身發明一個新的腳本語言。當時網景公司(Netscape)的高層對這個問題爭論不休。在這些喋喋不休的爭論裏,時間走到了1995年,這一年發生了一件創造歷史的大事件編程語言Java橫空出世,Java憑藉「一次編寫,處處運行的」強大宣傳,大有將來主宰的霸氣,這些讓網景公司(Netscape)高層們一會兒被Java所俘獲,如是網景公司(Netscape)和sun公司結盟,網景公司(Netscape)不只容許Java程序以applet的形式嵌入到瀏覽器,直接在瀏覽器裏面運行,甚至還打算把Java做爲腳本嵌入到網頁,只是最後發現網頁會變的過於複雜而放棄,可是JavaScript的Java印記永遠都揮之不去。編程
事情的轉折發生在1995年4月,網景公司(Netscape)錄用了Bremdan Eich(布蘭登·艾奇)(雖然Bremdan Eich(布蘭登·艾奇)是JavaScript的祖師爺,可是他的介入或許也是JavaScript悲劇的開始)。咱們仍是接着說網景公司(Netscape)吧,1995年5月,網景公司(Netscape)作出了決策,將來的網頁腳本語言必須看上去和Java足夠類似,可是比Java簡單,使得非專業的網頁做者能很快的上手。瀏覽器
Bremdan Eich(布蘭登·艾奇)被任命爲這個簡化版的Java的設計師。可是Bremdan Eich(布蘭登·艾奇)對Java一點興趣都沒有,爲了應付公司的安排的任務,他只用10天時間就設計出了JavaScript。悲劇就這麼誕生了。app
Brendan Eich的主要方向和興趣是函數式編程,網景公司招聘他的目的,是研究將Scheme語言做爲網頁腳本語言的可能性。Brendan Eich本人也是這樣想的,覺得進入新公司後,會主要與Scheme語言打交道。(沒想到美國公司也有這樣的惡習,我之前有家公司很是的BT,特別是對剛畢業或者工做時間不長的程序員,你想作Java我恰恰不給你作,讓你作C#,你想作C#,別天真,你去倒騰Java,不少程序員就是這麼被致殘的)。編程語言
10天誕生一種語言,無論怎麼說我仍是把Brendan Eich當神看。可是神創造世界也不能太一蹴而就了,咱們這些凡夫俗子不少時候作個小功能模塊若是領導就給你10天時間,也會叫苦不迭的,10天誕生一種語言這不是神仍是啥啊。因爲JavaScript設計的時間實在過短,致使不少細節考慮不周,所以JavaScript寫出的程序混亂不堪,成了許多程序員的夢魘,差點被人拋棄,直到ajax的出世,才讓人們終於找到理由忍受他的畸形。 函數式編程
總的來講啊,Brendan Eich設計思路是這樣的:函數
- 借鑑C語言的基本語法;
- 借鑑Java語言的數據類型和內存管理;
- 借鑑Scheme語言,將函數提高到"第一等公民"(first class)的地位;
- 借鑑Self語言,使用基於原型(prototype)的繼承機制。
因此,JavaScript語言其實是兩種語言風格的混合產物(簡化的)函數式編程+(簡化的)面向對象編程。這是由Brendan Eich(函數式編程)與網景公司(面向對象編程)共同決定的。學習
無論怎麼說,JavaScript和Java是有關係的,JavaScript裏面有Java的思想。因此說JavaScript和Java無關是不正確的。
其實一直到如今Brendan Eich仍是看不起討厭Java。假如不是公司決策Brendan Eich絕對不會把Java做爲JavaScript的設計原型,即便是如今,Brendan Eich仍是討厭本身的做品。他曾經說過:「與其說我愛JavaScript,不如說我恨它。它是C語言和Self語言的產物。十八世紀英國文學家約翰遜博士說得好:'它的優秀之處並不是原創,它的原創之處並不優秀。」
我第一次接觸JavaScript面向對象編程時候,是忍住刺痛和模糊看完的,那時只是獵奇,堅持看完也只不過是爲了要保持良好的學習態度,並且當時對JavaScript有誤解,以爲JavaScript面向對象編程是代碼愛好者的遊戲,使用價值不大,可是當我接觸到一些優秀的JavaScript源碼後我才發現,JavaScript面向對象編程用途是如此之多令我歎爲觀止,最後總結出一個結論:最好的JavaScript代碼都應該是面向對象的。
那麼JavaScript裏是如何實現繼承的?JavaScript的繼承機制如何?
首先JavaScript裏面沒有"子類"和"父類"的概念,也沒有"類"(class)和"實例"(instance)的區分,全靠一種很奇特的"原型鏈"(prototype chain)模式,來實現繼承。
網景公司在發明與設計JavaScript的目標,其中很重要的兩點:
1. 簡易版的Java;
2. 簡易,簡易仍是簡易。
Brendan Eich設計JavaScript的時候引入了Java一個很是重要的概念:一切皆對象。既然JavaScript裏面有了對象,那麼設不設計繼承就是困擾Brendan Eich的一個問題,若是真是要設計一個簡易的語言其實能夠不要繼承機制,繼承屬於專業的程序員,可是JavaScript裏那麼多的對象,若是沒有一種機制,他們之間將如何聯繫了,這必然會對編寫程序的可靠性帶來很大的問題,可是引入了繼承又會使用JavaScript變成了完整的面向對象的語言,從而提升了它的門檻,讓不少初學者望而卻步,折中之下,Brendan Eich仍是選擇設計繼承,但毫不是標準的繼承(說道這裏我想起了一樣使用EMCAScript標準設計的語言ActionScript,它裏面就有很完整的繼承,作起來很愜意,我常想這是否是JavaScript之後的趨勢,說不定哪天JavaScript會變的揯更完美寫了?)。折中是指Brendan Eich不打算引入類(class),這樣JavaScript至少看起來不像面向對象的語言了,那麼初學者就不會望而卻步了(這是欺騙啊,進來後倒騰死你,這就是所謂的關門打狗了)。
Brendan Eich思考以後,決定借鑑C++和java的new命令,將new命令引入了JavaScript,在傳統的面向對象的語言裏,new 用來構造實例對象,new 會調用構造函數,可是傳統面向對象的語言new 後面的是類,內部機制是調用構造函數(constructor),而Brendan Eich簡化了這個操做,在JavaScript裏面,new 後面直接是構造函數,如是咱們能夠這麼寫一個Person類:
6 |
var per = new Person( 'Brendan Eich' ); |
這樣就建立了一個新的實例了。可是new有缺陷。用構造函數生成實例對象是沒法沒法共享屬性和方法,例以下面代碼:
07 |
var per1 = new Person( 'Brendan Eich' ); |
08 |
var per2 = new Person( 'IT民工' ); |
09 |
per2.nation = 'China' ; |
10 |
console.log(per1.nation); |
11 |
console.log(per2.nation); |
每個實例對象,都有本身的屬性和方法的副本。這不只沒法作到數據共享,也是極大的資源浪費。和JavaScript工廠模式的缺點同樣,過多重複的對象會使得瀏覽器速度緩慢,形成資源的極大的浪費。
考慮到這一點,Brendan Eich決定爲構造函數設置一個prototype屬性,這個屬性都是指向一個prototype對象。下面一句話很重要:全部實例對象須要共享的屬性和方法,都放在這個對象裏面;那些不須要共享的屬性和方法,就放在構造函數裏面。
實例對象一旦建立,將自動引用prototype對象的屬性和方法。也就是說,實例對象的屬性和方法,分紅兩種,一種是本地的,另外一種是引用的。如是咱們能夠改寫下上面的程序:
06 |
Person.prototype = {nation: 'USA' }; |
08 |
var per1 = new Person( 'Brendan Eich' ); |
09 |
var per2 = new Person( 'IT民工' ); |
11 |
console.log(per1.nation); |
12 |
console.log(per2.nation); |
當咱們這樣寫程序時候Person.prototype.nation = 'China'; 全部實例化的類的nation都會變成China。
因爲全部的實例對象共享同一個prototype對象,那麼從外界看起來,prototype對象就好像是實例對象的原型,而實例對象則好像"繼承"了prototype對象同樣。prototype只是提供了實現JavaScript繼承的一個很方便的途徑和手段。