1.1 物件與類別
今天你會了解一個典型的 JavaScript 程式是如何運作的。而最重要的消息是:每個 JavaScript 程式都是由類別和物件組成的。JavaScript 是一個面向物件的語言,所有東西都是物件:數字、字串、函數,甚至是類別。
那麼類別是什麼呢?
我先從一個比喻開始。想像一下你想要製作一艘小船。首先你需要製作設計圖,然後把它交給工廠,在那裡他們會根據設計圖製造小船。或者十艘。事實上,多少艘都可以。重要的是,根據一張設計圖可以建造十艘相同的小船。
在 JavaScript 程式設計中也是一樣的。
設計圖
程式設計師就像是設計師,只是設計師畫出設計圖,而 JavaScript 程式設計師則寫出類別。然後根據設計圖創造出零件,根據類別創造出物件。
我們先寫出類別(做出設計圖),然後在程式執行時,JavaScript 會根據這些類別創造出物件。就像小船是根據設計圖創造出來的一樣。
設計圖只有一個,但小船可以有很多艘。小船不同,它們有不同的名字,裝載不同的貨物。但它們非常相似:它們都是具有相同結構的小船,可以執行類似的任務。
或者還有一個比喻...
蟻巢
蟻巢是一個很好的例子,展示了物件之間的互動。在一個簡單的蟻巢中有三種螞蟻:女王、戰士和工人螞蟻。
每種螞蟻的數量不同。女王就一個,戰士有幾十個,而工人螞蟻有幾百個。三個類別和幾百個物件。螞蟻相互之間以嚴格的規則進行互動,同類型的螞蟻與其他類別的螞蟻一起工作。
這個例子非常合適。在一個典型的程式中也是一樣。有一個主要的物件,創造出其他類別的物件。這些物件開始相互之間和程式的「外部世界」互動。在這些物件內,它們的行為是嚴格編程好的。
這兩個解釋是同一枚硬幣的兩面。真相在中間。第一個例子(設計圖和小船)展示了類別和這個類別的物件之間的關係。比喻很有力。而第二個例子(蟻巢)展示了在程式運行過程中物件和已寫類別之間的關係。
首先你得為程式中的所有物件寫出類別,然後還得描述它們的互動。聽起來有點複雜,但實際上比你想像的要簡單。
在 JavaScript 中,程式運行時的所有實體都是物件,而撰寫程式則歸結於描述物件之間互動的方法。物件簡單地呼叫彼此的方法,並傳遞所需的數據。
文檔
那麼如何知道哪些數據要傳遞給方法?這一切早在你之前已經想好了。
通常每個類別都有一個描述,說明它的用途。通常每個公開方法也有描述:它做什麼,需要傳遞哪些數據。
使用類別必須大致知道它的功能,還有確切知道每個方法的功能。完全不需要知道它如何實現。就像一根魔法棒。
來看看這段代碼 - 文件複製:
const fs = require('fs');
// 打開文件
const src = fs.createReadStream('source.txt');
const dst = fs.createWriteStream('destination.txt');
// 複製 source.txt 的內容到 destination.txt
src.pipe(dst);
// 複製完成後關閉文件
src.on('end', () => {
src.close();
dst.close();
});
如果逐行閱讀這段代碼,可以大致猜到它的功能。雖然這需要經驗和練習。經過一段時間,這段代碼會變得熟悉和易懂。
1.2. 程式設計
設計程式是一種藝術。這既簡單又困難。簡單在於沒有嚴格的規則:不禁止就允許。而困難也是因為這個原因:有太多方法可以做事情,不容易找到最佳方法。
設計程式就像寫一本書。一方面,你只是寫字母、單詞、句子。另一方面,故事情節、角色性格、內部矛盾、衝突、敘述風格、懸念等都很重要。
最重要的是要明白,寫代碼是給其他程式設計師看的。
開發任何產品都涉及到變更:這裡添加,那裡刪除,這裡重新設計。通過這樣的小迭代,誕生了大型、巨型和超級項目。
對代碼的主要要求是它應該對其他程式設計師來說是可以理解的。錯誤但易懂的代碼可以修正。正確但難懂的代碼則無法改進。只能丟掉。
那麼如何寫出好的、可理解的代碼呢?
為此需要做三件事:
- 在方法內寫出好的、可理解的代碼——這是最簡單的
- 決定程式中應該有哪些實體
- 正確地將程式劃分為邏輯部分
這些概念背後是什麼呢?
在方法內寫好代碼
如果你的英文水平至少是初級,可能已經注意到有時候代碼讀起來很像英文句子:
class Cat extends Pet
— 類別 Cat 繼承類別 Petwhile (stream)
— 當流不為空 ...a < b ? a : b
— 如果a
小於b
,返回a
,否則返回b
這樣做是有意的。JavaScript 是幾個可以讓你寫出自我描述代碼的語言之一:代碼不需要注釋就可以理解。好的 JavaScript 代碼中的許多方法讀起來就像英文句子。
在寫代碼時,你的任務就是讓代碼盡量簡單和精簡。只需思考你的代碼有多容易閱讀,你就會朝著正確的方向前進。
在 JavaScript 中,習慣上寫易讀的代碼。最好每個方法都能完整顯示在螢幕上(方法長度 20-30 行)。這是整個 JavaScript 社群的共識。如果代碼可以改善,就應該改善。
學習寫好代碼的最佳方式就是不斷練習。寫大量的代碼,研究他人的代碼,請更有經驗的同事審閱你的代碼。記住,當你對自己說「這樣也行」時,你的進步就停止了。
決定程式中應該有哪些實體
你需要寫出對其他程式設計師來說是可理解的代碼。如果 10 個程式設計師中有 9 個在設計程式時用類別 A、B 和 C,那麼你也應該在你的程式中使用類別 A、B 和 C。 你應該寫出其他人能理解的代碼。
優秀、運行快速、非典型的代碼是糟糕的代碼。
你需要學習他人的專案:這是繼承 IT 行業數十年智慧的最佳、最快和最容易的方法。
順便說一下,你手邊已經有一個很棒、受歡迎、文檔完整的專案——React。從它開始。
研究類別和類別結構。思考為什麼有些方法是靜態的而有些不是。為什麼方法有這樣的參數而不是其他。為什麼有這些方法,為什麼類別名稱如此,在這些封裝中。
當你開始明白所有這些問題的答案,你就能寫出其他人能理解的代碼。
不過,我還是要警告你遠離 D3.js 中的方法的代碼。許多方法的代碼為了速度最大化重寫,其可讀性成疑。
正確地將程式劃分為邏輯部分
通常會將任何程式劃分為部分或模塊。每個部分負責程式的一個方面。
就像電腦有主機、顯示器、鍵盤,這些都是獨立的、彼此依賴性較低的部分。而且它們的互動是標準化的:USB、HDMI 等。如果你把咖啡灑在鍵盤上,你可以直接在水龍頭下沖洗,晾乾後繼續使用。
而筆記本是單體架構的例子:邏輯部分存在,但結合更緊密。Macbook Pro,如果要清洗鍵盤,需要拆解一半的筆記本。濺灑在筆記本上的咖啡則是需要訂購新機的理由。千萬別灑。
1.3 創建自己的類別
你剛開始學習程式設計,所以應該從小處開始——學習創建自己的類別。
當然,你已經創建過類別,但需要學習瞭解程式應該有哪些類別,它們的名稱應該是什麼,應該有什麼方法。以及它們如何相互作用。
實體列表
如果不知道從何開始,那就從頭開始。
在設計程式開始時,你可以簡單地寫下程式中應該有的實體(物件)列表。然後按照這樣的原則編程:每個實體都是一個獨立的類別。
例子
假設你想寫一個象棋遊戲。你需要這樣的實體:象棋棋盤和 6 種棋子。棋子行走方式不同,有不同的價值——這是獨立的類別是合理的。而且在一開始,類別越多越好。
很少見到那種會寫出十個類別而不是兩個類別的新手程序員。反之,喜歡只寫一個或兩個類別的是新手。那麼多點類別吧,程序員們。你的代碼會讓所有人看得更明白,除了可能你自己 😛
象棋
假設我們決定為象棋寫類別:這些類別會是什麼樣的呢?
棋盤是個 8x8 的數組?最好為它創建一個獨立的類別,在其內部保存數組的引用。這樣你就可以給“象棋棋盤”類別添加許多有用的方法,例如檢查格子是空的還是滿的。
總之,開始時可以遵循這個原則:程式有不同的實體,而實體有一個類型。這個類型就是類別。
GO TO FULL VERSION