以JavaScript觀點來看 C++ template
在從 C++ Template 到 Java Generic,一步一步來一文,我用 Java 的泛型語法改寫了一個 C++ 樣板類別。 我也用 PHP、JavaScript 和 Ruby 來做同樣的事,看看這些動態語言有沒有泛型處理能力。
我要用 JavaScript 改寫的 C++ 樣板類別,其源碼同從 C++ Template 到 Java Generic,一步一步來。本文不再重複,直接說明 JavaScript 的改寫過程。
JavaScript 改寫過程
刪掉 private, public
,將變數型態換成 var
。
在 JavaScript 世界中,類別功能是透過 function object 實現,所以類別的建構子就是函數本身。將關鍵字 class
改成 function
,建構子參數跟著移到第一行。更多關於 JavaScript 實現類別的細節,請看 JavaScript的中介編程與反射能力示範、掌握 JavaScript 的「封裝」特性, part 1。
透過 undefined 或 arguments
判斷參數狀態設定實體初始狀態。
無參數建構子: N() {d = 0}
,意即 arguments.length == 0
時, d 之初值為0。
單參數建構子: N(int v) {d = v}
,意即 v 存在且為數值時, d 之初值為 v。
將上述 C/C++ 中分成兩個函數撰寫的流程彙整後即為下列流程:
當我們利用函數覆載撰寫多個建構子時,我們腦中就應該浮現出上述的配對流程, 而且事實上,編譯器內部也是使用著相同的配對流程決定該調用哪個建構子。 一般而言,靜態語言將這些動作內隱在編譯動作中,而動態語言則是顯露於程式碼。
將 C/C++ 的 method 定義語法改成 JavaScript 的寫法:
以 JavaScript 改寫類別 Cx 不需要特殊的樣板語法。
緊接著上面的內容,接著的要改寫 C++ 的 main()
。在 JavaScript 中不需要指示程序進入點,直接寫即可。
JavaScript 的變數不用宣告型別,寫 var 即可,由右值的實體決定左值的型別。 C# 3.0 引入了類似觀念,稱為隱含型別,而且關鍵字就是 var
。所以在 C# 3.0 的程式碼中看到 var n = new N(1);
時,請勿訝異。但是 JavaScript 的變數可以再次指派其他型別的資料給左值;C# 3.0 則在第一次指派後便固定型別,之後不可指派其他型別的內容給變數。
在 C++ 中的樣板類別 Cx ,到了 JavaScript 中之後,跟一般的類別沒兩樣。 因為動態語言的語義,基本上就是泛型的。
有些沒接觸過動態語言的人,對於泛型有一種奇怪的誤解,他們認為動態語言並沒有泛型語法,所以動態語言沒有泛型能力。我在C++和動態語言的泛型一文中曾經駁斥過這一論點。從語意看,動態語言其實就是泛型的。
移除 C++ 型別資訊,以 JsvaScript 語法改寫的 N, M, S 類別定義,也僅僅只剩兩行程式碼不同,這意味著我們可以進一步重構彙整。而且 JavaScript 做起來也不難。
樂多舊回應