工作上的需要,被迫上線學習Flutter,看了下文檔和線上的專欄,人老了,怕容易忘記,記錄下筆記,如果有錯誤的地方,煩請糾正。
一、Dart簡介
Dart是Google在2011年10月正式發佈的編程語言,起初的定位是運行在瀏覽器的腳本語言。是Google大神由於不滿JavaScript開發的程序後期難維護問題,而新研發的一種面向對象編程語言。然而nodejs的出現,JavaScript很快覆蓋了全棧,很多手機應用和桌面應用也成爲了JavaScript的宿主容器。這使Dart始終不溫不火,這麼多年來內置Dart VM的瀏覽器廠家也只有Google自己的產品Chrome(現在好像已經移除)。
很多人都有疑問,爲什麼JavaScript那麼火,而Dart的開發者那麼稀缺,Flutter會選擇Dart作爲基礎語言去研發呢?這不會提高開發者的介入成本,不利於推廣嗎?個人感覺應該以下幾個原因:
- Dart是Google自主研發產品,可以避免很多類似Oracle和Android的爭議問題。
- 自主研發語言,可以靈活迭代,爲Flutter架構的形成做最有力的支撐。
- Dart 尋求轉型,想彎道超車進入移動開發的領域
那麼Google選擇了用Dart語言開發Flutter框架,除了我們分析的客觀原因外,Dart本身有哪些特性是值得Flutter去選擇的?
二、Dart特性
- Dart是聲明式佈局語言,易於閱讀和可視化,可以不通過可視化構建器,通過熱重載直接真機調試。
- 同時支持JIT(即時編譯,JavaScript,Python)和AOT(運行前編譯,C,C++)
Dart在開發階段,使用了JIT編譯,這可以提高它的研發效率,降低研發週期。Flutter最受歡迎的熱重載,正是因爲這一特性。而發佈的時候使用AOT,就不用像RN那樣,在JavaScript和原生中建立低效的方法調用映射,因此,Dart具有運行速度快,執行性能好的特點。 - Drat是單線程模型,不需要像多線程那樣處理資源共享和數據同步問題,這也就意味着一個函數執行,就將執行到函數結束爲止,期間不會被其他Dart代碼所打斷。Dart的Isolate(隔離區)不會共享內存,幾個單獨的worker之間,通過事件循環在事件隊列中進行通信(類似Node)。
三、Dart基礎語法
Dart的運行依賴於Dart VM,大家可以通過安裝Dart SDK,來體驗Dart。安裝過程以MacOS爲例子,可以通過brew安裝
brew tap dart-lang/dart
brew install dart
接着在VSCode安裝Dart插件和code runner插件即可在vscode中體驗Dart編程。
跟很多編程語言一樣,Dart同樣以main函數作爲執行入口
void main() {
print('hello world');
}
Dart變量
Dart可以通過var關鍵字創建變量,當使用var時,類型是通過編譯器推斷決定.
var name = 'tony';
print(name is String); // true
在默認情況下,未初始化的變量值爲null,所以我們不需要擔心無法判斷一個傳遞過來的變量是undefined還是null(JavaScript的表示淚目),所以不需要各種if else。
var name;
print(name); // null
Dart類型
Dart是類型安全的語言,一切皆爲對象的設計思路,任何類型都是對象類型,都繼承了頂層的Object。類如bool,int,null,函數,都是繼承於Object。
String name;
print(name is Object); // true
bool isPig;
print(isPig is Object); // true
int num;
print(num is Object); //true
void fun() {}
print(fun is Object); //true
-
布爾類型
在Dart中,使用bool關鍵字來定義布爾類型,而布爾類型只有兩個值,true和false,它們都是編譯時常量。
var c1 = true; var c2 = false; print(c1 is bool); // true print(c2 is bool); // true
-
數值類型
在Dart中,使用num關鍵字來定義數值類型,num有兩個子類,分別爲int代表整數類型和double代表浮點類型
num n = 10; print(n is int); // true num m = 1.1; print(m is double); // true
除了常見的基本運算符,比如 +、-、*、/,以及位運算符外,你還能使用繼承自 num 的 abs()、round() 等方法,來實現求絕對值、取整的功能。你會發現,這些常見的運算符都繼承於num
-
字符串類型
在Dart中,String 由 UTF-16 的字符串組成。你可以使用${}內嵌表達式在字符串中,如果是一個表示符,可以省略{}
var name = 'chong'; print('my name is $name'); // my name is chong print('toUpperCase: ${name.toUpperCase()}'); //toUpperCase: CHONG
字符串的拼接,與JavaScript一樣,Dart用“+”運算符來拼接。
var x1 = 'chong'; var x2 = '...'; print(x1 + x2); // chong...
對與多行字符串的拼接,Dart提供了類似JavaScript的模版字符串功能。用三個單引號或者三個雙引號聲明
var str = ''' my name is chong '''; print(str); /* my name is chong */
-
集合類型
在Dart中,集合類型包含了數組類型和字典類型,分別對應List和Map,聲明和使用,都跟Javascript差不多
var name = ['zhangsan', 'lisi']; name.add('wangwu'); name.forEach((f) => print('$f')); // zhangsan lisi wangwu var map = {"name": 'chong', "sex": 'boy'}; map['n'] = 'hello'; map.forEach((k, v) => print('$k: $v')); // name: chong sex: boy n: hello
在定義name時,編譯器會推斷該List爲List,所以如果add的是個int或者其他類型,會類型錯誤。同理 map 會被推斷成Map<String, String>,當然,也可以從定義的時候設定類型,而避免推斷錯誤。
var map = <String, String>{"name": 'chong', "sex": 'boy'}; map['n'] = 'hello'; map.forEach((k, v) => print('$k: $v')); // name: chong sex: boy n: hello
Dart常量
Dart中定義常量的關鍵字有兩個,const和final,const的使用方法跟JavaScript的一樣。const和final的區別主要是const是在編譯時期已經確定的值,而final可以定義運行時的值,一旦運行結束,即不可改變。
```
var x = 10;
var y = 2;
final z = x / y;
print(z); // 5.0
const h = x / y;
print(h); // Error
```
Dart運算符
Dart的大多數運算符與其他編程語言的類似。有幾個比較特殊的運算符,用來簡化處理null的情況
-
??運算符,x??y,表示x爲空時,取y的值,x非空時,取x的值
var x; var y = 10; var z = x ?? y; print(z); // 10
-
?.運算符,x?.y 如果x爲null,跳過該語句,避免報錯
var x; print(x?.y); // null
-
??=運算符, x??=y,如果x爲null,把y賦值給x。如果x不爲null,跳過。
var x = 10; var y = 20; x ??= y; print(x); // 10 var x; var y = 20; x ??= y; print(x); // 20
在Dart中,一切皆對象,所以運算符也是對象成員函數中的一部分。當你在某些應用場景需要複寫運算符時,Dart也提供了複寫機制,只要通過 operator 關鍵字複寫即可.
class Demo {
var x, y;
Demo(this.x, this.y);
Demo operator +(Demo z) => Demo(x + z.x, y + z.y);
bool operator ==(Demo v) => v.x == x && v.y == y;
}
var x = Demo(3, 3);
var y = Demo(2, 2);
var z = Demo(1, 1);
print(x == (y + z)); // true
四、函數
Dart的函數由返回值、函數名、參數、函數體4部分組成,函數也是對象,它的類型爲Function,這也意味着函數可以被定義爲變量和作爲函數參數。
bool isCheck(int x, int y) {
return x == y;
}
void printBool(Function check) {
print('${check(1, 1)}');
}
printBool(isCheck); // true
Dart函數也支持箭頭表達式,使用方法跟Javascript一致。如上面的例子可以簡化爲
bool isCheck(int x, int y) => x == y;
void printBool(Function check) => print('${check(1, 1)}');
printBool(isCheck); // true
作爲集大多數語言優點爲一身的編程語言,Dart設計非常靈活的函數傳參設計。設計了通過{}指定傳參,設置了通過[]設置可選參數。這也使Dart的代碼更加簡潔優雅。不會像JavaScript一樣,如果函數需要三個參數,前兩個爲空時,必須佔位。下面通過一個例子來記錄一下Dart函數的傳參。
void demo1({int x, int y}) => print('$x,$y');
demo1(y: 2); // null,2
void demo2(int x, [int y]) => print('$x,$y');
demo2(1); // 1,null
demo2(1, 2); // 1,2
void demo3(int x, int y) => print('$x,$y');
demo3(1, 2); // 1,2
demo3(1); // Error
void demo4(int x, {int y}) => print('$x,$y');
demo4(1); // 1,null
demo4(1, y: 2); // 1,2
demo4(y: 2); // Error
五、類
對象是類的實例,在Dart裏,所有對象都繼承了頂層的Object,Dart中的類定義,實例話,方法引用,跟JavaScript ES6差不多。差別點是Dart中通過 “_” 來表示私有,聲明變量和方法時,在前面加上下劃線,表示爲private,沒加的,表示爲public。
class Cat {
var color, tail; // 顏色、尾巴
Cat(this.color, this.tail);
printInfo() {
print('這是一隻${color}毛髮, ${tail}尾巴的貓🐱');
}
}
var cat = new Cat('藍色', '長');
cat.printInfo(); // 這是一隻藍色毛髮, 長尾巴的貓🐱
-
構造函數
Dart中,類的構造函數有同名構造函數和命名構造函數兩種,同名構造函數,如上面代碼所示,與類同名。而命名構造函數,用以下方式定義
class Cat { var color, tail; // 顏色、尾巴 Cat(this.color, this.tail); Cat.defaut(var color) : this(color, '短'); // 重定向構造函數,用":"符號調用 printInfo() { print('這是一隻${color}毛髮, ${tail}尾巴的貓🐱'); } } var cat2 = Cat.defaut('白色'); cat2.printInfo(); // 這是一隻白色毛髮, 短尾巴的貓🐱
-
複用
在面向對象編程語言中,複用是個很重要的概念,很多編程語言都有繼承承,接口等概念,來實現代碼的複用。Dart也不例外,Dart中,也引入了繼承,接口的概念。
class Animal { var color, tail; Animal(this.color, this.tail); printInfo() { print('這是一隻${color}毛髮, ${tail}尾巴的貓🐱'); } } class Cat extends Animal { var type = '大型'; Cat(color, tail, {type}) : super(color, tail); @override printInfo() { print('這是一隻${color}毛髮, ${tail}尾巴的貓🐱,屬於${type}貓科'); } } class Dog implements Animal { @override var color, tail; @override printInfo() { print('這是一隻小狗'); } } var cat = new Cat("黑色", "長")..printInfo(); // 這是一隻黑色毛髮, 長尾巴的貓🐱,屬於大型貓科 var dog = new Dog()..printInfo(); // 這是一隻小狗
除了繼承和接口實現複用外,Dart還提供了Mixins方式。Mixins的中文意思是混入,就是在類中混入其他功能。在Dart中可以使用mixins實現類似多繼承的功能。
class Poultry { printInfo() { print('這是一種家畜'); } } class Big with Poultry {} var big = new Big().printInfo(); // 這是一種家畜