- JavaScript語言精髓與編程實踐(第3版)
- 周愛民
- 3336字
- 2020-07-02 15:37:31
前言
語言
語言是一種交流工具,這約定了語言的“工具”本質,以及“交流”的功用。“工具”的選擇只在于“功用”是否能達到,而不在于工具是什么。
在數千年之前,遠古祭師手中的神杖就是他們與神交流的工具。祭師讓世人相信他們敬畏的是神,而世人只需要相信那柄神杖。于是,假如祭師不小心丟掉了神杖,就可以堂而皇之地再做一根。甚至,他們可以隨時將舊的換成更新的或更舊的神杖,只要他們宣稱這是一根更有利于通神的神杖。對此,世人往往做出迷惑的表情或者歡欣鼓舞的姿態。今天,這種表情或姿態一樣會出現在大多數程序員聽聞新計算機語言被創生的時刻。
神杖換了,祭師還是祭師,世人還是會把頭叩得山響。祭師掌握了與神交流的方法(如果真如同他們自己說的那樣),而世人只看見了神杖。
所以,泛義的工具是文明的基礎,而確指的工具卻是愚人的器物。
分類法
在我看來,在JavaScript的進化中存在著兩種與分類法相關的核心動力:一種促使我們不斷地創造并特化某種特性,另一種則不斷地混合種種特性。更進一步地說,前者在于產生新的分類法以試圖讓語言變得完美,后者則通過混淆不同的分類法,以期望通過突變而產生奇跡。
二者相同之處在于都需要更多的分類法。于是我們看到,在二十年之后,JavaScript語言中有了動態的、靜態的、命令式的、說明式的、串行的、并行的等特性。然而拋開所有這些致力于“創生一種新語言”的魔法,到底有沒有讓我們在這浩如煙海的語言家族中,找到學習方法的魔法呢?
我的答案是:看清語言的本質,而不是試圖學會一門語言。當然,這看起來非常概念化。甚至有人說我可能是從某本教材中抄來的,另外一些人會說我試圖在這本書里宣講類似我那本《大道至簡》里的老莊學說。
其實我感覺很冤枉。我想表達的意思不過是:如果你想把一副牌理順,最好的法子,是回到它的分類法上,要么從A到K整理,要么按四個花色整理。畢竟,兩種或更多種分類法作用于同一事物,只會使事物混淆而不是弄得更清楚。
這本書
時至今日,離這本書第1版的發布已經過去十多年的時間了。我承認在之前的版本中,許多內容是通過對引擎或解釋器源碼的分析,以及對一些語言特性的表現進行反推而得來的。因此早期的一些內容并不能深刻、準確地反映JavaScript語言中的事實,又或者存在錯誤。更關鍵的地方在于,并沒有什么資料可以給出確定的事實或指出這些錯誤。如此,以至于在本書第2版發布時,我也只是匆匆地添加了一些有關ECMAScript 5(ECMAScript也簡稱為ES)規范中的內容,而未能對全書進行及時更新。
事實上我當時并沒有看到ES5的偉大之處。后來隨著ECMAScript新版本的推出,ES5中所蘊含的力量漸漸釋放出來,隨著ES6一直演進到現在的ES2019,我們見證了JavaScript最有活力、最精彩的時光。然而這本書早期版本中的內容也漸漸蒙塵,成為故紙堆中的不實傳言。于是,我終于下定決心,圍繞ECMAScript來重新解釋整個JavaScript核心,并在整本書的“多語言范型的整合”的大框架下重新開始寫它的第3版,即你現在讀到的這個版本。這顯然意味著我在這一版中將更加尊重ECMAScript規范,并同時降低了對引擎差異性的關注。另外,我對書中“編程實踐”的部分也進行了重新規劃,讓它們分散于每章的末尾,以便讀者可以有選擇地閱讀,以及有針對性地分析這些實踐案例。
然而無論如何,這本書都不是一本讓你“學會某種語言”的書,也不是一本讓初學者“學會編程”的書。閱讀本書,你至少應該有一點編程經驗,而且要擯棄某些偏見(例如,C語言天下無敵或JavaScript是新手玩具等)。
最后,你還要有很多耐心與時間。
問題
1.這本書可能會在不同章節反復講同一個問題,這是因為從不同的視角看相同的問題,其實結論并不相同(而JavaScript正好是一門多范型的語言)。
2.這本書會有極少數內容是與ECMAScript或現實中的特定運行期環境不同的,如果存在這種情況,本書一定會詳述其緣由。
3.這本書重在解釋原理,而不是實踐。
4.這本書與許多同類書相比,有著非常多的廢話—尤其對于那些打算通過這本書學習如何使用JavaScript的讀者來說。但這本書的特點,或許就在于說了一門具體語言之外的許多廢話。
5.從純粹討論“如何使用JavaScript”的角度來講,本書在功能點上寫得有些碎片化,這會導致許多內容中出現指向其他章節的交叉引用。這是本書從多語言范型角度對知識結構進行重新規劃的結果。
為什么
無論是出于作者的身份,還是之于讀者的期望,我都希望你在閱讀本書的過程中能多問幾個“為什么”。有疑與設疑,是本書與他書在立足與行文上的根本不同。
例如,在JavaScript中,函數參數是允許重名的,但是一旦使用了默認參數,就不允許重名了。關于這個問題,在ECMAScript中是有講解的,它詳細地用算法約定了這個語言特性。并且如果你深究一下,還會發現函數參數的初始化可以分成兩類:綁定變量名和綁定初始器,一旦啟用后一種方式,那么函數參數就不能重名了。再進一步,你會發現這個“初始器”是通過一個類似“鍵值對”的表來保存參數名和初始化表達式的,因為鍵不能重復,所以參數名也就不能重復……
是的,我們確實可以通過精讀ECMAScript來知道上述特性,了解它的成因和原理。然而倘若我們多問一下“為什么它這么設計”,大多數人就答不出來了。
因為ECMAScript中根本沒有寫。ECMAScript只說了“如何實現”,從來沒說“為什么這么設計”。這就好像有一本制造手冊放在你的手邊,即便你精讀每一章、研習每一節,其最終結果也只能做到“精確地制造”,而這個東西為什么造成這個樣子,又或者某一個參數設置為什么是5.01而不是4.99,你永遠也不知道。
例如這個問題:為什么“允許重名”這個特性不見了?
歷史
■ 2020.06《JavaScript語言精髓與編程實踐》(第3版)(當前版本)
本書第3版邀請了賀師俊(hax)、王保平(玉伯)和程劭非(winter)三位老師為本書寫推薦序,另外節選了《程序原本》一書的內容作為本書代序,并大幅更新了前言。全書內容重寫與重校,數易其稿,歷時三年終成。
本書新添加了第4章和第7章,分別討論靜態語言特性(主要是指結構化的方法與基本原理),以及并行語言特性。后者的部分內容涉及并發特性及其實現。在這一版中,將之前版本中關于“編程實踐”的大章刪除,分散在各章后分別討論實踐案例。
■ 2012.03《JavaScript語言精髓與編程實踐》(第2版)
本書第2版節選了《動態函數式語言精髓》一書的序作為代序。主要添加了ES5相關的內容,并將“編程實踐”中的內容從Qomo項目替換為QoBean項目。
這是一個改動較少的修訂版本。
■ 2009.03《動態函數式語言精髓》(電子書)
這本電子書是作為本書第1版的精簡版由InfoQ發布的。與《主要程序設計語言范型綜論與概要》類似,這本電子書回歸了我原本著述本書的目的,希望能通過對JavaScript的深入研究來切入對語言本質的討論。
正是這些關于語言的探索,最終幫助我完成了《程序原本》一書(2012—2016年)。
■ 2008.10《主要程序設計語言范型綜論與概要》(電子書)
這是一份對本書第1版的摘引,并作為一本獨立電子書發布。主要側重于語言范型的綜論,針對JavaScript的相關討論較少。
■ 2008.03《JavaScript語言精髓與編程實踐》第1版
本書正式發行。
慣例
1.類名或構造器函數名以大寫字符開始,例如,MyClass。
2.變量名或一般函數名以小寫字符開始,例如,myObject。
3.關鍵字或引用代碼中的變量名使用等寬字體,例如,yield。
4.正文中的英文采用一般字體,例如,JavaScript。
5.方法名或函數名在引用時會加括號,如apply(),如果不使用括號,則表明它們在上下文中應該被理解為屬性、構造器名或類名,例如,obj.constructor。
6.對象內部方法(通常在ECMAScript中規定)會以一對方括號標示,例如,[[call]]。
7.若非特殊說明,ES5/ES5.1分別指ECMA-262 edition 5/5.1,ES6/ES7/ES8分別指ECMA-262 edition 2015/2016/2017。
8.為了避免行文中不斷出現“從ESx版本開始,支持某某特性”的字樣,本書將基于ES2019講述,但在第3章與第6章的實踐中,部分ECMAScript規范章節編號指向的是ES2017。
9.所有在JavaScript示例代碼中出現的名稱都是按照JavaScript慣例命名的,如一般標識符以小寫字符開始,類、單例類或構造器以大寫字符開始;不使用下畫線作為分隔符。但是,如果一個變量聲明的目的是表明某種強調的語義效果,或是一個未經實現的工具函數/狀態,那么它將使用下畫線來分隔,并盡量表達一個有完整語義的定義。如果一個聲明以下畫線開始,那么它將表達ECMAScript規范中的例程,或引擎實現中的內部例程(使用下畫線的標識符,在源代碼中也可能會以斜體表示)。
10.源代碼中的斜體字通常用于表達語法概念,而非一個實際可用的標識符或聲明。
讀者服務
微信掃碼回復:38669

■ 獲取博文視點學院20元付費內容抵扣券
■ 獲取免費增值資源
■ 獲取精選書單推薦
■ 加入本書讀者交流群,與作者互動