Douglas Crockford:javascript——the Good Parts@2008
JavaScript: 優良部分 (The Good Parts) – 主要論點闡述
道格拉斯.克洛克福特 (Douglas Crockford) 所著的《JavaScript: 優良部分》一書,其核心論點在於強調 JavaScript 雖然因其開發歷史與標準化過程而包含許多設計上的瑕疵與問題,但其語言核心中蘊藏著一套強大、優雅且富有表達力的「優良部分」。作者認為,透過識別這些優良特性,並嚴格避免使用「劣質部分」(Bad Parts)與「糟糕部分」(Awful Parts),開發者可以編寫出更可靠、更易讀且更易於維護的 JavaScript 程式碼。這本書的宗旨並非全面介紹 JavaScript 語言,而是提供一個經過篩選、更安全的語言子集,鼓勵讀者專注於利用這些精心挑選的特性。
主要論點詳解:
-
JavaScript 的雙重性:優良部分與糟糕部分並存
這是本書最基礎且貫穿始終的論點。作者直言不諱地指出,JavaScript 存在許多問題,包括設計缺陷、行為不一致以及可能導致錯誤的特性。然而,在這些缺點之下,是其作為第一個普及的 Lambda 語言(受 Lisp 和 Scheme 啟發)所擁有的函數式程式設計能力、基於原型的繼承機制以及表達力豐富的物件和陣列字面值表示法。本書的核心任務就是將這「美好的、優雅的、富有表達力的語言」從「一堆充滿良好意圖和錯誤的蒸騰物」中挖掘出來。 -
專注於優良部分以提升程式碼品質
作者強烈主張,為了寫出更好的程式,程式設計師應該只使用語言的優良部分,並避免使用劣質部分。這並非因為某些特性不實用,而是因為它們可能導致難以偵測的錯誤、降低程式碼的可讀性或移植性。透過使用語言的一個更嚴格、更小的子集,可以減少學習時間、提高程式碼的健壯性並簡化維護工作。這種限制性的方法實際上能夠釋放 JavaScript 真正的潛力,使其成為一種優秀的動態程式語言。 -
函數是 JavaScript 的基石與最優良特性
書中將函數視為 JavaScript 最傑出的部分,認為它「幾乎一切都做對了」。函數是 JavaScript 中的第一類物件(first-class objects),這意味著函數可以像其他值一樣被儲存、作為引數傳遞或作為返回值。結合 JavaScript 的詞法作用域(lexical scoping),函數催生了多種強大的程式設計模式,例如:- 閉包 (Closure): 內部函數可以記住並存取外部函數的變數和引數,即使外部函數已經執行完畢。這使得函數可以擁有私有狀態,是資訊隱藏和模組化的關鍵。
- 模組 (Module Pattern): 利用函數和閉包來建立封裝的單元,暴露一個公共介面,但隱藏其內部狀態和實現細節,從而大幅減少對全域變數的依賴。
- 回呼函數 (Callbacks): 處理非同步事件的標準方式,通過將函數作為引數傳遞,在操作完成時執行。
- 遞歸 (Recursion): 函數呼叫自身來解決較小的子問題,適用於處理樹狀結構等問題。
- 記憶化 (Memoization): 函數通過物件儲存先前計算的結果,避免重複計算,提高效能。
-
級聯 (Cascade): 通過讓方法返回
this物件,可以在一個語句中連續呼叫同一個物件的多個方法,提高程式碼的表達力。 -
柯里化 (Curry): 通過將一個函數和部分引數組合,產生一個新函數,減少函數呼叫的複雜性。
這些模式展現了 JavaScript 函數的高度彈性和強大功能。
-
物件與原型繼承:理解其動態與無類別的本質
JavaScript 採用基於原型的繼承機制,物件直接從其他物件繼承屬性,這與傳統的類別繼承不同。作者指出,許多開發者試圖將類別繼承模式直接套用到 JavaScript,導致挫敗。書中提倡理解並利用 JavaScript 原型的本質:- 物件字面值 (Object Literals): 提供一種簡潔方便的語法來建立新物件,是 JSON 格式的靈感來源。
- 動態性 (Dynamism): 物件是動態的鍵值對集合,可以隨時新增、修改或刪除屬性,沒有類型的限制。
- 原型鏈 (Prototype Chain): 屬性查找會沿著原型鏈向上遍尋,直到找到屬性或到達原型鏈頂端 (Object.prototype)。
-
繼承模式 (Inheritance Patterns): 書中介紹了幾種實現繼承的模式,包括偽傳統式 (Pseudoclassical,基於構造函數和
new關鍵字,被認為是語言的劣質部分之一)、原型式 (Prototypal,基於Object.create,直接物件繼承) 和函數式 (Functional,基於函數和閉包,提供私有性和更好的封裝) 等,並傾向於後者。
-
識別並避開特定的「劣質」與「糟糕」部分
書中詳細列舉了應避免使用的語言特性,並解釋了其原因:- 全域變數 (Global Variables): 被視為最糟糕的部分,導致命名衝突、難以偵錯和降低程式碼可靠性。應盡量使用模組和閉包來避免。
-
==與!=相等運算子: 由於其自動型別強制轉型(type coercion)規則複雜且容易產生非預期的結果(例如' ' == 0為true),應一律使用===與!==嚴格相等運算子。 -
分號自動插入 (Automatic Semicolon Insertion): 雖然看似方便,但可能隱藏錯誤,尤其是在
return語句後換行時。應始終明確使用分號。 -
with語句: 使得變數綁定不確定,降低程式碼可讀性和可預測性,應完全避免。 -
eval函數及其變體 (如Function構造函數、字串引數的setTimeout/setInterval): 帶來安全漏洞、效能損耗並阻礙程式碼分析。應完全避免。 -
缺少區塊作用域 (Lack of Block Scope): JavaScript 只有函數作用域,區塊 (
{}) 不會建立新的作用域。這與許多 C 類語言不同,可能導致混淆。建議在函數開頭聲明所有變數。 -
其他問題特性:
continue語句(可讀性差)、switch語句的穿透(容易忘記break)、缺乏花括號的單行控制流語句(容易引入錯誤)、++和--運算子(鼓勵寫作過於緊湊難懂的程式碼)、位元運算子(在 JavaScript 的浮點數系統中效率低下且可能與邏輯運算子混淆)、new運算子(若忘記使用會導致嚴重錯誤)、typeof對null和陣列的判斷不準確、NaN的特殊行為(NaN === NaN為false)、parseInt的八進制問題、+運算子的兩重性(加法或字串連接)、浮點數精度問題、假的陣列 (arguments物件和typeof對陣列的誤判)以及hasOwnProperty可能被覆蓋等。
-
強調程式碼風格和 JSLint 工具的重要性
由於 JavaScript 語言本身的寬鬆和容錯性,程式碼品質在很大程度上依賴於程式設計師的紀律。良好的、一致的程式碼風格可以顯著提高程式碼的可讀性和可維護性。作者在書中展示了一種清晰的風格,並鼓勵讀者遵循。同時,作者也介紹了他開發的 JSLint 工具,這是一個 JavaScript 語法檢查器,能夠分析程式碼並報告其中包含的劣質部分和潛在問題,幫助開發者遵守語言的優良子集,彌補語言本身在編譯時缺乏的嚴格性。
總而言之,《JavaScript: 優良部分》的核心思想是通過對語言進行嚴格的篩選和限制,將一個充滿陷阱的語言轉變為一個強大且可靠的開發工具。它不是一本面面俱到的語言參考手冊,而是一份關於如何避開雷區並充分利用 JavaScript 精華部分的指導。
comments
comments for this post are closed