- JavaScript悟道
- (美)道格拉斯·克羅克福德
- 3701字
- 2021-07-28 17:49:44
第 0 章 導讀 ○ ○ ○ ○ ○
隨機事件之繁復,以及一猿執筆于案前能寫何字,凡此種種皆不可控。
——George Marsaglia
JavaScript并不完美,但是這不妨礙它運行起來。
本書的受眾有兩類:一是有一定JavaScript基礎并且想更深刻地理解其內在邏輯和用法的讀者,二是有一定編程經驗并且想了解一門新語言內在邏輯的讀者。
也就是說,其實本書并不適合初學者閱讀。期待將來的某一天,我也可以專門為初學者寫一本書。但這本不是,畢竟它有一定的深度。如果你僅略讀本書,可能收獲甚微。
本書不會講解JavaScript引擎或者虛擬機,而會講解JavaScript這門語言本身,以及每一位JavaScript開發人員都需要明確的事情。本書可能會讓你重新認識JavaScript,包括它是如何運作的、怎樣讓它變得更優秀,以及如何更好地使用它。本書還會教你如何正確地看待JavaScript,以及如何正確地用JavaScript進行思考。在本書中,我會依照ES6版本來講解,并不會贅述ES1、ES3以及ES5等版本的細節。這些內容實際上并不重要,畢竟我們只需要關注當下的JavaScript就好了。
本書并不面面俱到,很多內容并未討論。如果我在書中沒有提到你關注的一些特性,那很有可能是因為它們設計得太糟糕了。還有,我不會花很多篇幅探討語法本身,畢竟大多數人對JavaScript的語法多少還是有一些了解的。如果你在語法等內容上需要幫助,可以參考JSLint網站上的相關內容。
我會在書中稍微提及JavaScript中比較有用的一些部分,例如原型(prototype)上的大多數內置方法。有一些在線精品資料庫也列出了這些內容。我個人極力推薦Mozilla基金會的資料庫。
編程語言的重要設計目標之一就是盡可能使其簡潔、優雅、邏輯性強,沒有各種奇怪的極端情況。然而事實上,JavaScript遠沒有達到這個目標。隨著越來越多的特性加入,每一次新版的發布都會使其變得越來越糟糕。現在這門語言充滿了各種奇怪的用法和邊界情況。本書會稍微提及這些奇怪的用法,以告訴大家其中潛藏著可怕的“怪物”。我們應當遠離這些東西,盡量待在這門語言干凈陽光的一面,這里已經有能讓你寫出好程序所需的一切了,不要讓自己墮入無邊黑洞。
10年前,我寫過一本關于JavaScript的神奇小手冊。雖然JavaScript表面一團糟,但其內在仍然是美好的。通過避其糟粕,你可以寫出出色的JavaScript代碼。這一點與某些編程專家的觀點相悖,他們認為精通一門語言的所有特性才能證明自己造詣高深。對于他們而言,特性就是用于掌握和精通的、不容辯駁,自然也就根本不存在糟糕的特性。這種觀點顯然是錯的,但很遺憾,目前它仍占據著主導地位。
事實上,真正的“精通”應該體現在代碼的可讀性、可維護性以及是否無錯上。如果你做到了這幾點,那就真的可以炫耀了。做一個謙遜的程序員吧。吾日三省吾身:自身可乎?工作可乎?可有提升乎?經驗之談,為炫技而過分使用各種特性,只會適得其反。
這是我用來提升自己所寫代碼的“不傳之法”:
如果一個特性時而有用,時而是個“坑”,并且有更好的選項,那么我們就應該始終選擇那個“更好的選項”。
也就是說,對于一門語言來說,我使用的一直是它能滿足我的“最小集”,這樣就能避免使用那些可能有“坑”的特性。這個對于我自己而言的“最小集”也并非一成不變,我一直在完善它。本書就記錄了我到目前為止對于JavaScript的相關思考。我之所以還能寫一些JavaScript的優點,是因為JavaScript確實有不少可取之處。雖然相較于10年前,JavaScript的精粹變少了,但留下來的那些精粹更顯閃耀。
近年來,JavaScript已經成了世界上最重要的編程語言之一。說來慚愧,我應對此負部分責任,在此先給讀者道個歉。多個新版ECMAScript規范的出臺并沒能解決JavaScript自身深層次的問題,反而創造了更多的問題。實際上,標準委員會修復問題的權力有限,讓這門語言野蠻發展的權力反倒大得很,放任其復雜性和怪異性一再增加。要是阻礙了JavaScript的發展(哪怕是往糟糕的方向發展),那么他們的樂趣何在?
人們不停地給老化的語言“整容”,拼命地往其中注入各種新的特性來穩住其流行地位,或者至少讓其看起來不那么“圡”1。與“代碼膨脹”一樣,“特性膨脹”過猶不及。我們更應該去發現JavaScript的內在美,而不是做各種表面功夫。
1該字古同“土”,由于外形看起來像“土到掉渣”,因此現在有時用于形容老掉牙。——譯者注
我推薦你閱讀ECMAScript規范。它雖然讀起來可能有些晦澀,但好在是免費的。
說實話,閱讀ECMAScript規范在一定意義上改變了我的人生。跟大多數開發人員一樣,我在使用JavaScript之前并沒有去系統地學習它。正因為如此,我當時認為這門語言很爛——各種運行行為令人困惑,就是讓人喜歡不起來。直到有一天閱讀了ECMAScript規范,我才發現JavaScript的絕妙之處。
0.1 異類
我有預感,本書會讓一些同僚感到不舒服。我是異類,正在挑戰一些守舊者的權威。我已經習慣這些了。多年前,我因為發現了JavaScript居然有精粹并將其整理成冊而飽受挑戰和攻擊。還有當我剛提出JSON(它現在已經成了時下最流行的數據交換格式)的時候,也是如此。
社區是有信仰的,哪怕這些信仰存在錯誤,社區成員也能從中獲益。因此,當信仰被人質疑時,社區成員就會覺得受到了威脅。對,我就是這個質疑的人。我對真理的渴求高于對社區利益的看重。恰恰就是這一點會讓很多人不高興。
我其實只是一個普通程序員,只想找到一個最佳實踐來寫出優美的代碼。雖然我的一些想法可能不對,但我也在思考如何糾正這些想法。我們這代程序員有很多思維模式已在FORTRAN時代固化,我覺得是時候踏出改變的一步了。不過,即使我處在一個極具創造性的行業中,變革仍然并非易事。
如果你認為自己被我這個異類的話冒犯了,那么我建議你將本書放回書架并遠遠走開。
0.2 代碼
本書的所有隨書代碼都可以免費獲取。你可以將其用于任何目的,但請不要拿它們“作惡”。如果有可能,我希望這些代碼能讓你做一些“好事”。
強烈建議你不要簡單地復制粘貼你并不理解的那些代碼。雖然我們經常戲稱自己是“復制粘貼工程師”,但這種做法實際上是很不可取的。這雖然比不上看都不看一眼就去安裝一款未知軟件那么蠢,但也實在算不上一種明智之舉。在當前的安全技術水平下,最好的安全過濾器就是你的大腦,請務必善用。
雖然我的代碼并不完美,但我認為跟我前幾年寫的代碼相比,它們至少還是有進步的。我個人著重在為這方面的進步而努力,并且希望能活到讓我的代碼達到完美的那一天。我希望你也能在這方面下功夫。你可以在本書的網站(How JavaScript Works)上查看勘誤表(erratums)2。在拉丁語中,erratum的復數形式是errata,但誰讓我用的是現代英語呢?在現代英語中,我們應該通過添加s或者es來構成復數形式,所以這里我用了erratums。如果要在保持傳統和與時俱進之間選擇,我選擇與歷史的車輪一起前進,以此來使世界更美好。
2要查看或提交中文版勘誤,請訪問圖靈社區本書頁面。——編者注
如果你發現了本書中的錯誤,請將勘誤發送至郵箱erratum@howjavascriptworks.com。謝謝。
0.3 未來
雖然本書的主題是JavaScript,但有時候我實際上是在講另一種可以取代JavaScript的語言。我堅信在JavaScript之后應該有一門語言脫穎而出。如果JavaScript是值得學習的最后一門語言,就真的太可悲了。我們應該為子孫后代找到這樣的下一門語言。這將是我們留給他們的珍貴寶藏。
我認為未來屬于孩子們,也屬于機器人。
當下和未來的互聯網需要下一代的編程范式,它應當是全局分布式的、安全的和事件化編程的。遺憾的是,當下包括JavaScript在內的幾乎所有編程語言依舊停留在舊的范式中,即本地化的、不安全的和順序化編程的。我把JavaScript看作一門過渡的語言。在JavaScript中使用最佳實踐可以很好地為我們未來理解新的編程范式做好準備。
0.4 語法
我認為1的英文拼寫是錯誤的,因此在書中用了自認為更正確的拼寫——wun。one這個單詞根本不符合任何發音規則,包括各種特殊規則。此外,用一個看著像0的字母作為表示1的單詞的首字母,本身就不合適。
不過,wun這個單詞對于大眾來說,看起來有點奇怪。之所以在書中采用這樣的拼寫,是因為我想通過此事讓你明白一個道理:對陌生事物產生的奇怪感覺并不能證明它是錯的。
單詞拼寫已然發生變革。例如,有些小家伙認為把through拼寫成thru會更好,因為他們覺得這個常用單詞有一半字母不發音毫無道理,用起來效率低下,也給學生造成了困惑。拼寫改革實際上是一次傳統與理性的對抗,有時候理性更容易獲勝。編程語言亦如此。如果你也覺得wun比one更有意義,那么請和我一起努力吧。
一般人在提到像1到10這類范圍的時候,通常將其理解為到10為止,而程序員則通常認為10是被排除在外的。這是由一些編程習慣造成的,比如在編程中起始編號一般是0而不是1。因此,我用“到”(to)來表示程序員日常認為的“到”,而用“過”(thru)來表示普通人認為的“到”。也就是說,“0到3”代表0、1、2,而“0過3”則代表0、1、2、3。簡而言之,“到”的語義為小于(<),而“過”則代表小于等于(≤)。
0.5 示例
我喜歡用正則表達式。然而,正則表達式其實是比較晦澀難懂的。我會在正則表達式中加入一些空白,使其看起來更規整易懂。實際上,JavaScript并不支持這樣規整的寫法。因此,你看到的如下代碼:
const number_pattern = / ^ ( -? \d+ ) (?: \. ( \d* ) )? (?: [ e E ] ( [ + \- ]? \d+ ) )? $ /;
在實際中則應該是這樣的:
const number_pattern = /^(-?\d+)(?:\.(\d*))?(?:[eE]([+\-]?\d+))?$/;
我實在忍不住在上面晦澀的正則表達式中加入了各種縮進和空格,好讓讀者讀起來一目了然。
在很多章節中,我會使用JavaScript表達式作為示例。通常,我會以一個不以分號(;)結尾的表達式來進行展示,后跟一句注釋(以//開頭)來表示其結果。
// 示例 3 + 4 === 7 // true NaN === NaN // false typeof NaN // "number" typeof null // "object" 0.1 + 0.2 === 0.3 // false 3472073 ** 7 + 4627011 ** 7 === 4710868 ** 7 // true
上述種種,終焉之前,皆有所釋。
- Learning LibGDX Game Development(Second Edition)
- 極簡算法史:從數學到機器的故事
- 數據庫程序員面試筆試真題與解析
- Cocos2d-x游戲開發:手把手教你Lua語言的編程方法
- JavaScript by Example
- Building a Quadcopter with Arduino
- Scala編程實戰(原書第2版)
- 零基礎輕松學SQL Server 2016
- Scala Reactive Programming
- 打開Go語言之門:入門、實戰與進階
- R語言數據可視化:科技圖表繪制
- 創意UI:Photoshop玩轉APP設計
- C語言程序設計教程
- 啊哈C語言!:邏輯的挑戰(修訂版)
- SCRATCH編程課:我的游戲我做主