- JavaScript語言精髓與編程實踐(第3版)
- 周愛民
- 4055字
- 2020-07-02 15:37:30
推薦序1 一本不是所有人都需要的好書
這個有點繞口的標題,是從豆瓣上本書第1版的一個書評標題照錄而來的。豆瓣上排名前列的評論還有“這是一本硬書”“國內技術原創書中稀有的‘異數’”等。實際上,我覺得不僅是國內,算上在市面上能看到的所有JavaScript相關的書,本書都絕對堪稱“硬書”“異數”。
傳統上,許多大部頭的JavaScript相關的圖書,會有大量篇幅介紹DOM相關的API和如何結合語言與平臺API進行Web前端編程,這些年也可能換成是Node.js的API和服務器端編程。從入門或進階來說,這樣的編排都是合適的,因為結合特定平臺和領域的具體編程實踐可以更快速地建立學習的正向反饋。專注JavaScript語言本身的書也不是沒有,ES6時代到來之后,頗有幾本書全面細致地介紹了JavaScript語言的新特性。甚至有很有名的書,會一直講到不為多數人所知的語言細節,受到中高級開發者的追捧。不過這些書還都是用來“學習”語言的書。
愛民的這本書,卻不是一本“學習”用的書,而是一本“闡釋”用的書。不要說JavaScript初學者,就算你有三五年甚至十年的JavaScript開發經驗,讀起這本書可能也不易。因為絕大部分開發者不習慣這樣思考問題。
比方說,這本書大的章節是按照結構化、面向對象、函數式、動態化等編程范式來展開討論的,最新版中還加入了“并行計算”。
有些讀者或許也看過一些談編程范式的書,甚至專門談在JavaScript語言中使用某一種編程范式的書(比如近年來隨著某框架而在JavaScript圈逐漸火起來的函數式編程),但這些書還都是引領你“學習”一個范式,教你“應用”一個范式的書。
愛民這本書的出發點與其他書不同,并不是為了學習、應用“范式”,而是為了分析“編程語言”,取之為線索。為此,需要系統性地逐一論述多種主要范式,然后將JavaScript語言的要素分解并歸納入不同范式下進行討論。需要注意的是,JavaScript語言與每種范式代表性的經典編程語言都有很大的不同。所以在這個過程中,讀者也可以注意體悟多種范式是以怎樣一種方式不完美卻可用地并存于JavaScript這門語言之中的。
在每章的開始,先有十數頁的概述來論述范式和其背后的思想源流,故這一部分幾乎總是要以跳出JavaScript這單一語言的視角來論述的。這些概述也絕不是簡單地從其他書或資料中拿一些內容拼湊而成的,而是愛民以自己數十年編程和架構的心得理解精煉而成的。光這些概述,在本書第1版出版時的技術圖書市場上前所未見,到今日JavaScript的相關圖書汗牛充棟,恐怕也仍然獨此一家。
不過,這也帶來一個問題,就是對于絕大多數讀者來說,概述可能反而比后續章節更難讀,初讀時一知半解。
這次愛民要出第3版,寄贈我一些樣稿,我讀到第4章概述中論及“結構化的疑難”是“抽象層次過低”,而“面向對象”范式正是對此的應答時,頗有茅塞頓開之感。但后來重新翻閱12年前愛民贈我的本書第1版,才發現已包含了這段論述。可見當年我恐怕也是囫圇吞棗,雖讀之也并不能領會消化。
然而即使我現在提到了這個段落,讀者可能特意去認真閱讀該段落,記住了、理解了,也不見得能產生直接的“用處”。
打個不一定恰當的比喻,金庸的《射雕英雄傳》中周伯通講《九陰真經》:“這上卷經文中所載,都是道家修煉內功的大道,以及拳經劍理,并非克敵制勝的真實功夫,若未學到下卷中的實用法門,徒知訣竅要旨,卻是一無用處。”
市面上大部分技術圖書,都是講“實用法門”的,偶爾講一點“拳經劍理”。愛民寫這本書的終極目標其實是傳授“內功大道”,為此拿了一門最流行的武功(語言)來拆解剖析,總結出其獨特的“拳經劍理”,以印證“大道”。在這個闡釋的過程中,“實用法門”講的不多,即使講了一些,也意不在此。
事實上,很多人只是想要“實用法門”的書,最好還是速成的。那就最好不要選本書了。這種需求也不好說錯。或許先講“實用法門”,再講“拳經劍理”乃至“大道”,才是符合普通人的認知規律的。
另一方面,即使一個人也有意于“拳經劍理”乃至“大道”,如果市面上全是講“實用法門”的書,他一直以來熟悉的只有這個套路,就會對其他模式不太適應。比如說,對一個語言特性的解說和評論,絕大部分圖書的講法主要基于“實用”,也就是,有什么用,怎么用,用起來順手不順手。但愛民這本書的視角就很不一樣,主要是基于“大道”和“拳經劍理”的內在邏輯進行推演。
需要理解的是,這兩個方向可能互相印證,也可能產生矛盾。編程語言和一切復雜的人造事物一樣,是不完美的。
這也會延伸到語言設計上。作為程序員,雖然看到新語言特性的介紹通常還都是從“實用”角度講解(宣傳)的,但在設計階段,其實要接受各個維度、不同層面的需求和約束。語言特性要平衡多種不同因素,平衡不了就要做取舍。但這個取舍到底是不是合適,就見仁見智了。
愛民在這次新版的第4章中花了不少篇幅討論目前stage 3的類字段(class fields)提案和他設計的替代性方案。這個提案比表面上看起來要復雜得多,無論是在委員會還是在社區里,不同的人的看法會非常不同,而且這種分歧貫穿了“大道”“拳經劍理”“實用法門”各個層面。需要注意,即使持同樣立場的人,比方說同樣反對現有提案,其背后的原因也可能截然不同,對解決路徑的判斷也會截然不同。TC39是基于一致同意的方式推進工作的。對于接受現有提案的人來說,即使其認知不同,但至少表面上是達成一致的。而對不同意現有提案的人,各有各的不同意,因而也無法達成一致。表現出來的結果,就是愛民在書中所說:“類字段提案提供了一個極具爭議的私有字段訪問語法,并成功地做對了唯一一件事情,讓社區把全部的爭議焦點放在了這個語法上”。這也是類字段提案的悲劇性之所在。
我認為,討論這個話題的價值,不在于給出一個答案(畢竟TC39都給不出令人滿意的答案),而是這個思考過程。在這個過程中,我們需要同時考慮“大道”(面向對象范式)、“拳經劍理”(JavaScript現有的語法和語義約定和約束,與后續提案的關系和協調性等)、“實用法門”(使用方式、如何滿足各種需求、代碼風格、性能……)等不同的層面。這是一個極好的思維訓練,在這個過程中,無論你得到怎樣的結論,都會對JavaScript語言有更深層次的認知和把握。而這樣的內容,也只能存在于“闡釋”之書中。
然后說說對“闡釋”可能存在的疑問。那就是多種不同的甚至矛盾的“闡釋”是否可以共存,有沒有一種解釋是最正確的,或者權威的。
舉一個小例子,typeof null為什么返回"object"?從歷史事實來說,根據Brendan Eich自己的說法,這是無心之失。但愛民的意見,這也可以理解為null實為對象類型的特殊值。6年前我在知乎上對這種“闡釋”做了較為詳細的解說。
按照一般認知,Brendan Eich自己的說法當然是最正確和權威的。然而有意思的是,前不久,在Allen Wirfs-Brock和Brendan Eich合作撰寫并提交給HOPL會議的論文JavaScript:The First 20 Years中寫道:
……令人困惑的是,typeof null會返回字符串值"object"而不是"null"。其實也可以說這與Java保持了一致,因為Java中的所有值都是對象,而null本質上是表達“沒有對象”的對象……根據Brendan Eich的回憶,typeof null的值是原始Mocha實現中“抽象泄露”的結果。null的運行時值使用了與對象值相同的內部標記值進行編碼,因此typeof運算符的實現就直接返回了"object"。
——引自doodlewind的中文譯本,原文在預印本第12頁
這篇權威論文同時列出了這兩種解釋。所以愛民很多年前的闡釋也算被“官宣”了。
有人可能要打破砂鍋問到底,到底哪一種才是“正確”的呢?其實我認為都是正確的。Brendan Eich的回憶可能是歷史真相,但當事人的回憶不一定是真相的全部。我們可以追問,為什么當初在實現的時候,對象和null共享了相同的標記值呢?一種解釋是,可能是當年有意識“根據Java的null值表示‘沒有對象’,來對JavaScript中的null值進行建模”的副產品,另一種解釋是編程中無意產生的結果。即使是后一種,如果考慮引擎是如何實現的,就會發現對象引用的內部表達肯定是一個內存地址,那么很自然就會以全0的地址代表null。那么可以說,導致這種“抽象泄露”本身的源頭是高層模型到具體實現的自然映射,偶然性中蘊含了必然性。另外,我們也可以追問,為什么當初標準化的時候,沒有對typeof null的結果提出異議呢?不太可能委員會中的所有成員都沒有發現,所以一個合理猜想是,發現這個問題的人也采用了類似愛民的闡釋對這個行為進行了“合理化”。
其實在日常生活中,有大量這種既是“機緣巧合”又“冥冥中自有定數”的事例,在技術領域其實也一樣。
這當然不是說,任意一種“闡釋”都是正確的,“闡釋”本身得自洽,然后有足夠的解釋效力,具有普適性,不會引發反例,引入一種“闡釋”的成本不應該大于收益,最后還要經得起“奧卡姆剃刀”原則的考驗。要做到這些是非常困難的,有時候是難以判斷的。包括本書對JavaScript語言的各種“闡釋”,肯定不是所有人都認同的,包括我自己,對其中某些部分也會有不同意見。但是程序員從“碼農”成長起來,可以進行更大范圍、更高層次的設計,乃至以成為像愛民那樣的“架構師”為職業目標,這就需要提升對各種不同“闡釋”的理解判斷及融會貫通的能力,并逐步形成自己對技術進行“闡釋”的能力。從這點來說,這本“硬書”在那么多JavaScript書中是獨具價值的。
當然,這樣的“闡釋”之書,啃起來不容易。借用一些豆瓣上的吐槽:
? ……本來一個點能說清楚的……跑離了卻又想繞回來,最后弄得這個點只有作者本人和少數明白人才明白,也不加個注釋說明。
? 書中的語言有些晦澀,讀起來不是很流暢。
? 有用,但啰唆;啰唆,但有用……一件簡單的事情要用上四五層比喻,還說不透。對于追求閱讀快感的人……有點隔靴搔癢的感覺。
這些評論絕不是惡意的,實際上這些評論者總體上都是贊許本書的,只是被我專撿了一些負面閱讀體驗的詞句。我自己當年讀本書第1版時也有同感。今天我讀樣稿時感覺倒是好了不少,可能是愛民做了一些優化,但估計更多是隨著年歲漸長,我本身的技術水平提升了,對“闡釋”之書的閱讀能力也提升了。尤其這一年以來,親身參與在TC39之中,感受到對JavaScript的“闡釋”即使在委員會里本身也是具有多重性和不確定性的,這產生了很多問題,但也是活力的一部分。所以對不同“闡釋”的包容和理解,乃是必需的。
不過即使考慮閱讀能力有所提升,本書的閱讀體驗和“流暢”“閱讀快感”也是不搭界的。這是讀者在讀本書前需要有的心理準備。
最后總結,“闡釋”之書定然“不是所有人都需要的”,但我個人希望這樣的書可以多來幾本。
賀師俊
2020年4月
- 大學計算機基礎(第二版)
- Mastering JavaScript Object-Oriented Programming
- PHP基礎案例教程
- Java EE框架整合開發入門到實戰:Spring+Spring MVC+MyBatis(微課版)
- 自然語言處理Python進階
- Getting Started with Greenplum for Big Data Analytics
- Learning FuelPHP for Effective PHP Development
- Access 2010數據庫應用技術(第2版)
- C語言程序設計實訓教程與水平考試指導
- 軟件體系結構
- Android智能手機APP界面設計實戰教程
- JavaScript Unit Testing
- Swift Essentials(Second Edition)
- VC++ 2008專題應用程序開發實例精講
- IBM DB2 9.7 Advanced Application Developer Cookbook