第209期 / March 5, 2015

分享到臉書!分享到維特!分享到噗浪!分享到Google+!分享到微博!轉寄友人友善列印

淺談新一代物件導向網頁語言-Google Dart

作者/林憲良

[發表日期:2015/3/5]

前言

隨著手持裝置的普遍與雲端服務的興起,網頁漸漸成為未來熱門的程式主流,網頁技術經過多年來的淬鍊已經成為一項非常成熟的技術,近年來,AJAX、HTML5、Http2.0、CSS3、ECMAScript陸續推陳出新,將網頁技術推向另一個境界。以現今的網頁技術來看,SPA(Single Page Application)為目前市場上的主流,SPA主打一個頁面就能完成多功能的操作與顯示,這個觀念是源自於AJAX與JavaScript的盛行,透過JavaScript與AJAX讓許多Server Side的工作可移至Client端完成,減少了與Server端的資料傳遞次數。

JavaScript為目前在普遍使用的網頁前端語言,市面上的瀏覽器幾乎都支援JavaScript,所以可跨平台瀏覽器執行。但JavaScript缺乏物件導向的概念,撰寫起來比較沒有主流物件導向程式語言般的容易理解。例如:在JavaScript中,物件中只有Property與Function的概念,所以物件的Constructor只是一個Function。JavaScript也沒有繼承與多型的用法。此外,JavaScript還有一個令開發人員頭痛的詬病,就是JavaScript會容忍Exception的發生,例如:在執行過程中使用一個不存在的Property,或將資料錯誤轉型成其他資料型別進行運算,這些本應該拋出的錯誤,JavaScript會忽略並繼續執行,使得開發人員不容易Debug。另外,JavaScript在效能上也有一些議題,例如:JavaScript在網頁的啟動時期,載入時的效能會很差;開發大型且複雜的網頁應用程式時效能不佳。這些問題常是大家深入探討的議題。

Google Dart

Google Dart是Google所提出的新一代網頁語言,由Google Chrome V8引擎團隊開發,主要目的有兩個,第一個目的為加速瀏覽器VM的執行效能,V8團隊在過去Chrome的經驗發現結構化的程式語言與簡潔的VM能夠提高瀏覽器的執行效率,故開發了Dart Web程式語言與Dart VM提高瀏覽器執行效能。Dart第二個目的為提供開發人員更加方便的開發環境。撰寫Dart時不僅可以使用簡單快速的使用Google提供的Library,也能將自己所撰寫的Library開放出去,提供其他開發人員或其他專案使用,大幅發揮Code Reuse的精神,另外,Dart有提供專門的開發工具,使用此開發工具可以更簡單的進行重構與Debug,比起JavaScript沒有專門的開發工具,相較起來方便多了。

Dart語言

Dart的撰寫方式為物件導向,它提供了抽象類別(Abstract Class)、Static Type…等物件導向常見的結構,這對習慣於物件導向開發的開發人員來說可以大大減少開發時間。接下來我們會使用程式碼的方式表現Dart語言的特色。

一、第一支Dart程式

在看第一支程式之前,要先提起一點,一個Dart應用程式中只能有一個.dart檔案。下列是一個基本的Dart程式範例。


《圖一》Dart基本程式範例



《圖二》圖一執行結果


Dart程式中只有一個main主程式進入點,除了main function外,你可以建立其他Top-Level的function,範例中建立了兩個function,一個為void function,另一個為return num資料型態的function。Dart在編譯時期可以分析expression進而判別function的回傳類別或變數的資料型態,因此在function上可以省略寫void或回傳的資料型態;在變數上則可以使用var匿名資料型態宣告。print為Dart所提供的顯示輸出的Top-Level function,較奇特的是變數在Dart中可以在雙引號中組成字串,在變數名稱前加上$就可在字串中代表變數。

二、資料型態(Build-in Data Type)

Dart中所有的資料型態的實體(instance)皆為物件(object),就算是基本資料型態也是物件,所以不像其他物件導向語言一樣,Dart任何資料型態的預設值皆為null。基本資料型態類型有數字(Numbers)、字串(Strings)、布林值(Booleans)、陣列(Array)、Maps、Symbols。數字資料型態有num、int、double,num為int與double的基底類別(base class),num提供基本的數值運算function,例如abs、cell、floor。
Dart字串型態可以使用兩個單引號或兩個雙引號區間表示,字串相加可以選擇性使用加號(+),將兩個雙引號區間或單引號區間的字串相鄰在一起在Dart中就是個合法的字串相加,例如:”I am””a Programmer”。

布林值方面,Dart與JavaScript不同是的Dart布林值只有true與false兩個值;而JavaScript則是可將1或不等於null的物件視為true,下列範例程式碼就表現出Dart與JavaScript在判斷布林值上的差異。


《圖三》Dart布林值執行範例



《圖四》圖三執行結果


在Dart Editor上執行JavaScript可行的程式碼時,Dart就會發生Type Error的Exception。

在Dart中,不管是陣列或集合都統稱為List,陣列的初始宣告只要在中括號內加入陣列元素就可以。Dart的陣列中的元素可以是動態類別,意思就是可以將不同資料型態的元素加入到同一個陣列中,Dart會在執行時期自動識別元素的類別。下列Dart的動態類別陣列範例程式碼。


《圖五》Dart List範例程式碼



《圖六》圖五執行結果


Map資料型態是數個Key-Value Pair的集合,類似Java中的Map與C#中的Dictionary。Map和陣列一樣也能同時存動態型態,每組Key-Value Pair的Key與Value的資料型態可不同,只要注意每個Key值皆是唯一的。

Symbol是Dart特有的資料型態,它的功用一般用不到,只用在當要進行Minify Dart程式碼時或將Dart轉成JavaScript的情況下,在轉的過程中,Compiler會將Symbol名稱轉成對應的字串值。

三、類別(Class)

Dart與JavaScript最大的差別在於它屬於物件導向概念的程式語言,那麼就要提到類別。先前有提到在Dart中所有的instance皆是物件,所以不管是哪個Class或Type,他們的基底類別(Base Class)皆為Object。Dart也提供多重繼承,只要用with連接欲繼承的類別就可以達到多重繼承的效果。以下為類別繼承的簡單範例程式碼。


《圖七》類別基本範例程式碼


範例程式碼中,共有四個Class,Animal為抽象類別,Animal有三個建構子(Constructor),Animal.SetLegAndName、Animal.SetLegs、Animal,Dart的Constructor不提供overload的功能,只能使用範例中具名建構子的方式,且具名建構子不能被子類別繼承。Animal有兩個private欄位: _leg與_name,與一個未實作的方法: echo()。在Dart中,只有public與private兩種可視性,private的方法或欄位命名會以”_”作為前綴詞,另外,命名方面,除了Class以開頭大寫為主,其他都用開頭小寫。Train也為抽象類別,在這只提供方法。Dog繼承Animal,在後面用with Test代表也繼承Train,Constructor繼承Animal的SetLegAndName,並實作了Animal的echo與Train的special2方法,在實作的echo方法中,我們可以看到”=>”符號,這種方式是Dart提供的Lamda方式寫法,當方法實作只有一行的情況下就可以省略撰寫大括弧與return。Human只繼承Animal,Constructor與Dog一樣繼承Animal的SetLegAndName,但Human中多了一個_hand 欄位,會在Constructor進行設定。Human中還提供取得四肢數量_fourLimbs的屬性(Property),回傳_legs與_hands的總和。

看完上面的類別基本範例之後,接著來看看Dart提供的類似Interface的作法,我們將上面的Train與Dog之間的關係改成interface實作,將上面的程式碼修改如下:


《圖八》Interface程式碼範例


主要差異為Dog改用implements來實作Train,使用implements意味著要重新實作Train的所有方法與欄位值,意思就是Dog將Train的所有內部成員定義都複製過來,細節需要重新定義實作,連在Train中有設定的欄位預設值,在Dog裡都要重新賦予值,但只需要取需要用的部分重新實作即可。

四、泛型(Generics)

許多高階物件導向語言如C#、Java、Swift...等都有提供泛型的實作方法,利用泛型可以讓指定的型別在執行時期帶入,增加程式碼對各種型別的支援彈性,以下為以泛型實作的簡單Stack範例程式碼:


《圖九》Dart泛型範例程式碼


在建立Stack的instance時,只要指定資料型態就能將Stack內的陣列指定為該資料型態,例如:var stack = new Stack();。

五、Exception處理

JavaScript本身有提供try…catch(err)的方式抓取Exception並進行對應的Exception處理作業,但在JavaScript對所有類型的Exception都用err來識別,當要針對多種Exception做特定處理時需要在去判斷Exception類型下功夫。Dart本身就有提供許多基本常見的Exception類型,例如:Out of memory、Invalid input、Incorrect state transitions、meaningless arguments…等。除此之外,Dart客製化Exception類別,只要繼承某個類型的Exception類別。要針對各種不同類型的Exception作處理時,使用一連串的try…catch就能達到效果,範例程式碼如下:


《圖十》Dart Exception處理範例



《圖十一》圖十執行結果


應用程式類型

Dart最特別的也最大的亮點就是Dart可跨平台開發,這裡的跨平台開發指的是你可以使用Dart語言來開發各種平台的應用程式,例如:網頁伺服器、網頁應用程式、手持裝置應用程式、Command-Line應用程式。Command-Line應用程式主要是用來設計網頁伺服器,就如NodeJS一樣,Dart是個可獨自在Client和Server上執行的Script語言。

Web Applications

Web Application基本需要兩個檔案,.html與.dart檔,當然,需要時CSS樣式檔也可加入,就像html裡使用JavaScript一樣,如果要在html裡引用Dart就須在<head>區間裡加入<script type=”application/dart” ></script>,在<script>區間內撰寫Dart Code或在<script>的src屬性指定.dart檔案位置。以下為一個新增備忘欄的網頁範例程式碼:


《圖十二》Dart Web Application範例程式碼(HTML)



《圖十三》Dart Web Application範例程式碼(Dart)


Dart在Web上的Coding方式和Command-Line應用程式雷同,但為了使用Web上相關的Dart API,必須import “dart:html”的Library。取得Html上的元件並對此元件進行操作或設定其觸發事件的對應處理是使用網頁程式語言常見的應用,在Dart中如何取得Html的元件呢?Dart使用querySelector(“”)來取得Html上的元件,傳入的字串和jQuery的表示方法一樣,”#”代表傳入指定ID的元件,”.”代表所有使用該CSS Class的元件。那如何設定元件的觸發事件呢?Dart使用類似jQuery的方式監聽觸發事件,例如:範例中ButtonElement使用_addBtn.onClick.listen(addToList),listen裡傳入的function必須要傳入Event的參數,透過Event參數可以知道一些資訊,例如:觸發的元件名稱、事件類型…等,這裡值得一提的是,你可以發現listen方法傳入一個方法的參數,沒錯,Dart提供一個Function型別,可以將function當作參數傳遞執行,就類似C#中的Func與Action。在範例中,我們將Note以物件方式表示,整個程式以物件導向的方式實作,可以發現程式碼變得更好理解與處理,這便是Dart強大之處。下圖為範例程式執行結果。


《圖十四》圖十二、十三程式執行結果


開發工具

Google專門為Dart設計了一套開發工具,Dart Editor。Dart Editor是以Eclipse為Base進行開發的Dart開發工具,所以在Dart Editor上可以看到許多Eclipse的功能。在早期,Dart執行時會直接執行在Dart VM上,此種方式執行的效能會較好,但因為目前支援Dart VM的瀏覽器只有Google Chrome與Chromium上,所以受限於瀏覽器支援上。但在目前的版本上,已經可以將Dart轉成JavaScript在各瀏覽器執行,但原生Dart的執行效能還是比轉譯出的JavaScript還好。


《圖十五》Dart Editor



《圖十六》Dart Editor內部版面配置


結論

Dart是一套物件導向的網頁程式語言,相較於JavaScript,Dart程式碼較好維護,若在Google的DartVM上執行Dart程式效能比JavaScript快上好幾倍。根據Google所提供的Benchmark,最新的DartVM執行效能上已超過JVM。下圖為DartVM與JVM執行效能的比較圖,更多的Benchmark可以在Google Dart官網詳閱(https://www.dartlang.org/performance/)


《圖十七》DartVM與JVM效能比較圖
(來源:http://www.infoq.com/news/2013/05/Dart-Java-DeltaBlue)


經過Google這幾年來的推廣,加上Google自家MVVM技術AngularDart的加持,Dart在大眾間的普及率愈來愈高,ECMAScript標準也在2014年正式納入Dart(ECMA-408),這對Dart的肯定又往前跨了一大步。儘管Dart普遍性提高,瀏覽器的支援程度畢竟一直是個問題,目前Internet Explore、FireFox、Safari…等知名瀏覽器並不打算將DartVM裝載至自家的瀏覽器內。雖然Dart有提供將Dart Code轉為JavaScript的方法,但無法在DartVM上執行就無法完全發揮Dart的效果,這真是唯一的遺珠之憾。

參考資料

1、End-to-end productivity with Dart
2、Latest Dart VM Beats JVM in DeltaBlue Benchmark
3、ECMA-408
4、Dart 語言中文站
5、限量ㄟ蓋步-Google Dart介紹