代碼練習(xí):DartPad
對比語言:JavaScript
1、程序入口
JavaScript:沒有入口函數(shù)沉噩。
Dart:必須有一個main()函數(shù)作為程序入口。
2柱蟀、控制臺輸出
JavaScript:console.log("hello,world!");
Dart:print('hello,world!');
3川蒙、dart數(shù)據(jù)類型
//int (一般占8個字節(jié))? ? ? ? ? ? ? ? ? ?
var count = 1;? ?or? ?int count = 1;
//double (一般占8個字節(jié))? ? ? ? ? ?
var a = 0.1;? ? or? ??double a =0.1;
//num(int和double的父類型长已,一般占8個字節(jié))
//String? ? ? ? ? ? ? ? ? ? ??
?var s = "dart"; or String s = 'dart';
//bool? ? ? ? ? ? ? ? ? ? ? ? ? ??
var find = true; or??bool find = true;
//List?
var arr = [1,2,3,4,5];??
List<String>?arr2 = ['hello','world',"123","456"];??
List flybyObjects = ['Jupiter', 'Saturn', 'Uranus', 'Neptune'];
//Map? ? ??
var image = new Map();
var image = { 'tags': ['saturn'], 'url': '//path/to/xxx.jpg'};?
var map={"a":"1","b":2,"c":3,4:5};
Map image = { 'tags': ['saturn'], 'url': '//path/to/xxx.jpg'};
注意:dart沒有l(wèi)ong和float類型
4畜眨、變量
JavaScript:無法定義變量類型,js沒有這種聲明方式:int count = 1术瓮。
Dart:是類型安全的康聂,你可以明確指定某個變量的類型,如int bool String胞四,也可以用var或 dynamic來聲明一個變量恬汁。盡管類型是必須的,但是dart的某些類型注釋是可選的辜伟,因?yàn)?b>dart會執(zhí)行類型推斷氓侧。Dart 沒有 public、private导狡、protected 這些關(guān)鍵字约巷,變量名以"_"開頭意味著對它的 lib 是私有的。
例如:
//JavaScript
var name = "JavaScript";
//Dart
String name1 = 'Dart';? ?或者? ? var name2 = 'dart';都是可以接受的旱捧,其中name2進(jìn)行了類型推斷独郎。
5、默認(rèn)值
JavaScript:未初始化的變量默認(rèn)值是undefined枚赡。
Dart:未初始化的變量默認(rèn)值是null氓癌。
注意,數(shù)字在dart語言中也被當(dāng)成對象标锄,所以即使是帶有數(shù)字類型的對象沒有給出初始化默認(rèn)值顽铸,那么該對象值就是“null”。
//JavaScript
var name;? ?// ==undefined
//Dart
String name;? // ==null
int a;? ? //? ==null
6料皇、檢查null或零
JavaScript:1或者任何非null對象的值被視為true谓松。
Dart:只有布爾值為true才被視為true。
// is運(yùn)算符用于判斷一個變量是不是某個類型的數(shù)據(jù)
// is!則是判斷變量不是某個類型的數(shù)據(jù)
var s ="hello";
print(s is String);// true?
var num =6;
print(num is! String);// true
// ~/是取整運(yùn)算符践剂,如果使用/則是除法運(yùn)算鬼譬,不取整
int k =1; int j =2;
print(k / j);// 0.5
print(k ~/ j);// 0
// as運(yùn)算符類似于Java中的cast操作,將一個對象強(qiáng)制類型轉(zhuǎn)換
(empasPerson).teach();
// ??=運(yùn)算符?如果 ??= 運(yùn)算符前面的變量為null逊脯,則賦值优质,否則不賦值
var param1 ="hello", param2 =null;?
?param1 ??="world";?
?param2 ??="world";
print("param1 = $param1");// param1 = hello?
print("param2 = $param2");// param2 = world
//??.運(yùn)算符在左邊為null的情況下會阻斷右邊函數(shù)的調(diào)用
var str1 ="hello world";
var str2 =null;
print(str1?.length);// 11
print(str2?.length);// null?
print(str2.length);// 報(bào)錯
//??運(yùn)算符在左側(cè)表達(dá)式為null的時候?yàn)槠湓O(shè)置右邊為默認(rèn)值
print(null??false);//false
print(false??11);//false
print(true??false);//true
7、final和const
如果你絕不想改變一個變量,使用final或const巩螃,不要使用var或其他類型演怎,一個被final修飾的變量只能被賦值一次,一個被const修飾的變量是一個編譯時常量(const常量毫無疑問也是final常量)避乏∫可以這么理解:final修飾的變量是不可改變的,而const修飾的表示一個常量拍皮。
注意:實(shí)例變量可以是final的但不能是const的
說明:
var count =10;
final Num = count;// final 只能賦值一次
const Num1 =10;// const賦值必須是編譯時常量
final和const的區(qū)別:
區(qū)別一:final 要求變量只能初始化一次歹叮,并不要求賦的值一定是編譯時常量,可以是常量也可以不是铆帽。而 const 要求在聲明時初始化咆耿,并且賦值必需為編譯時常量。
區(qū)別二:final 是惰性初始化爹橱,即在運(yùn)行時第一次使用前才初始化萨螺。而 const 是在編譯時就確定值了。
8宅荤、function
//JavaScript
function fn(){
return true;
}
//Dart
// 聲明返回值
int add(int a,int b){
return a + b;
}
// 不聲明返回值
add2(int a,int b) {
return a + b;
}
// =>是return語句的簡寫
add3(a, b) => a + b;
main() {
print(add(1,2));// 3
print(add2(2,3));// 5
print(add3(1,2));// 3
}
9屑迂、命名參數(shù)、位置參數(shù)冯键、參數(shù)默認(rèn)值
命名參數(shù)
定義命名參數(shù)時惹盼,你可以以?{type paramName}?或者?{paramName: type}?兩種方式聲明參數(shù),而調(diào)用命名參數(shù)時惫确,需要以?funcName(paramName: paramValue)?的形式調(diào)用
注意:命名參數(shù)被{ }括了起來手报,類似于map的形式,調(diào)用的時候需要 參數(shù)名:參數(shù)值
sayHello({String name}) {
print("hello, my name is $name");
}
sayHello2({name: String}) {
print("hello, my name is $name");
}
main() {?
// 打印 hello, my name is zhangsan??
sayHello(name:'zhangsan');??
// 打印 hello, my name is wangwu?
?sayHello2(name:'wangwu');}
位置參數(shù)
使用中括號[]括起來的參數(shù)是函數(shù)的位置參數(shù)改化,代表該參數(shù)可傳可不傳掩蛤,位置參數(shù)只能放在函數(shù)的參數(shù)列表的最后面,如下代碼所示:
sayHello(String name, int age, [String hobby]) {// 位置參數(shù)可以有多個陈肛,比如[String a, int b]
StringBuffer sb =new StringBuffer();?
sb.write("hello, this is $name and I am $age years old");
if(hobby !=null) {?
?sb.write(", my hobby is $hobby");
?}
print(sb.toString());
}
main() {
// hello, this is zhangsan and I am 20 years old
sayHello("zhangsan",20);
// hello, this is zhangsan and I am 20 years old, my hobby is play football
sayHello("zhangsan",20,"play football");
}
參數(shù)默認(rèn)值
// 命名參數(shù)的默認(rèn)值
int add({int a, int b =3}){// 不能寫成:int add({a: int, b: int = 3})
return a + b;
}
// 位置參數(shù)的默認(rèn)值
int sum(int a,int b, [int c =3]){
return a + b + c;
}
10揍鸟、類
類的定義與構(gòu)造方法
Dart中的類沒有訪問控制,所以你不需要用private, protected, public等修飾成員變量或成員函數(shù)句旱,一個簡單的類如下代碼所示:
class Person{
String name;?
int age;
String gender;
Person(this.name,this.age,this.gender);?
sayHello() {
? ? print("hello, this is $name, I am $age years old, I am a $gender");
?}
}
上面的Person類中有3個成員變量阳藻,一個構(gòu)造方法和一個成員方法,看起來比較奇怪的是Person的構(gòu)造方法谈撒,里面?zhèn)魅氲?個參數(shù)都是this.xxx腥泥,而且是沒有大括號{}包裹的方法體,這種語法是Dart比較獨(dú)特而簡潔的構(gòu)造方法聲明方式啃匿,它等同于下面的代碼:
Person(String name, int age,String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
要調(diào)用Person類的成員變量或成員方法蛔外,可以用下面的代碼:
var p =new Person("zhangsan",20,"male");?
p.sayHello();// hello, this is zhangsan, I am 20 years old, I am a male
p.age =50;??
p.gender ="female";??
p.sayHello();// hello, this is zhangsan, I am 50 years old, I am a female
類除了有跟類名相同的構(gòu)造方法外蛆楞,還可以添加命名的構(gòu)造方法,如下代碼所示:
class Point{?
num x, y;?
Point(this.x,this.y);
// 類的命名構(gòu)造方法
Point.origin() {??
? x =0;??
? y =0;??
?}
}
main() {
// 調(diào)用Point類的命名構(gòu)造方法origin()
var p =new Point.origin();
var p2 =new Point(1,2);
}
Dart中使用extends關(guān)鍵字做類的繼承夹厌,如果一個類只有命名的構(gòu)造方法豹爹,在繼承時需要注意,如下代碼:
class Human{
String name;?
Human.fromJson(Map data) {? ?
print("Human's fromJson constructor");?
?}
}
class Man extends Human{??
Man.fromJson(Map data) :super.fromJson(data) {??
? print("Man's fromJson constructor");?
?}
}
由于Human類沒有默認(rèn)構(gòu)造方法尊流,只有一個命名構(gòu)造方法fromJson帅戒,所以在Man類繼承Human類時,需要調(diào)用父類的fromJson方法做初始化崖技,而且必須使用Man.fromJson(Map data) : super.fromJson(data)這種寫法,而不是像Java那樣將super寫到花括號中钟哥。
有時候你僅僅只是在某個類的構(gòu)造方法中迎献,調(diào)用這個類的另一個構(gòu)造方法,你可以這么寫:
class Point{
num x, y;
Point(this.x,this.y);
// 命名構(gòu)造方法調(diào)用了默認(rèn)的構(gòu)造方法
Point.alongXAxis(num x) :this(x,0);}
類的成員方法
一個類的成員方法是一個函數(shù)腻贰,為這個類提供某些行為吁恍。上面的代碼中已經(jīng)有了一些類的成員方法的定義,這些定義方式跟Java很類似播演,你可以為某個類的成員變量提供getter/setter方法冀瓦,如下代碼:
class Rectangle{
num left, top, width, height;//?
構(gòu)造方法傳入left, top, width, height幾個參數(shù)
Rectangle(this.left,this.top,this.width,this.height);
// right, bottom兩個成員變量提供getter/setter方法
num get right => left + width;
set right(num value)=> left = value - width;??
num get bottom => top + height;
set bottom(num value)=> top = value - height;
}
抽象類和抽象方法
使用abstract修飾一個類,則這個類是抽象類写烤,抽象類中可以有抽象方法和非抽象方法翼闽,抽象方法沒有方法體,需要子類去實(shí)現(xiàn)洲炊,如下代碼:
abstract class Doer{
// 抽象方法感局,沒有方法體,需要子類去實(shí)現(xiàn)
void doSomething();
// 普通的方法
void greet(){?
? print("hello world!");??
}}
class EffectiveDoer extends Doer{
// 實(shí)現(xiàn)了父類的抽象方法
void doSomething(){?
?? print("I'm doing something...");?
?}}
運(yùn)算符重載
Dart中有類似于C++中的運(yùn)算符重載語法暂衡,比如下面的代碼定義了一個向量類询微,重載了向量的+ -運(yùn)算:
class Vector{?
num x, y;??
Vector(this.x,this.y);?
?Vector operator +(Vector v) =>new Vector(x + v.x, y + v.y);?
?Vector operator -(Vector v) =>new Vector(x - v.x, y - v.y);?
?printVec() {?
?? print("x: $x, y: $y");? }}
main() {?
Vector v1 =newVector(1,2);??
Vector v2 =new Vector(3,4);??
(v1 - v2).printVec();? // -2, -2
(v1 + v2).printVec();? // 4, 6
}
枚舉類
使用enum關(guān)鍵字定義一個枚舉類,這個語法跟Java類似狂巢,如下代碼:
enum Color { red, green, blue }
mixins
mixins是一個重復(fù)使用類中代碼的方式撑毛,比如下面的代碼:
classA{??
a() {
? ? print("A's a()");??
}
}
classB{?
?b() {? ?
?print("B's b()");??
}
}
// 使用with關(guān)鍵字,表示類C是由類A和類B混合而構(gòu)成
classC= A with B;
main() {?
?C c =new C();??
c.a();? // A's a()
c.b();? // B's b()
}
靜態(tài)成員變量和靜態(tài)成員方法
// 類的靜態(tài)成員變量和靜態(tài)成員方法
class Cons{
static const name ="zhangsan";
static sayHello() {
print("hello, this is ${Cons.name}");
? }
}
main() {??
Cons.sayHello(); // hello, this is zhangsan
print(Cons.name); // zhangsan
}
11唧领、異步編程
Dart和JavaScript一樣藻雌,都支持單線程執(zhí)行
JavaScript:promise對象表示異步操作的最終完成(或失敗)及其結(jié)果值
Dart:future來表示異步操作
12疹吃、async和await
async函數(shù)聲明定義了一個異步函數(shù)蹦疑。
JavaScript:async函數(shù)返回一個promise,await運(yùn)算符用來等待promise萨驶。
async? _getIPAdress(){
?const url = "https://httpbin.org/ip";
const response = await fetch(url);
const json = await respons.json();
const data = await json.origin;
console.log(data);
}
Dart:async函數(shù)返回一個future歉摧,函數(shù)的主體是稍后執(zhí)行,await運(yùn)算符用來等待future。
_getIPAdress() async{
final?url = "https://httpbin.org/ip";
var request = await HttpRequest.request(url);
String ip = json.decode(request.response.responseText)['origin'];
print(ip);
}