代碼練習(xí):DartPad
對(duì)比語(yǔ)言:JavaScript
1、程序入口
JavaScript:沒(méi)有入口函數(shù)。
Dart:必須有一個(gè)main()函數(shù)作為程序入口。
2、控制臺(tái)輸出
JavaScript:console.log("hello,world!");
Dart:print('hello,world!');
3、dart數(shù)據(jù)類(lèi)型
//int (一般占8個(gè)字節(jié))? ? ? ? ? ? ? ? ? ?
var count = 1;? ?or? ?int count = 1;
//double (一般占8個(gè)字節(jié))? ? ? ? ? ?
var a = 0.1;? ? or? ??double a =0.1;
//num(int和double的父類(lèi)型,一般占8個(gè)字節(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沒(méi)有l(wèi)ong和float類(lèi)型
4、變量
JavaScript:無(wú)法定義變量類(lèi)型,js沒(méi)有這種聲明方式:int count = 1。
Dart:是類(lèi)型安全的,你可以明確指定某個(gè)變量的類(lèi)型,如int bool String,也可以用var或 dynamic來(lái)聲明一個(gè)變量。盡管類(lèi)型是必須的,但是dart的某些類(lèi)型注釋是可選的,因?yàn)?b>dart會(huì)執(zhí)行類(lèi)型推斷。Dart 沒(méi)有 public、private、protected 這些關(guān)鍵字,變量名以"_"開(kāi)頭意味著對(duì)它的 lib 是私有的。
例如:
//JavaScript
var name = "JavaScript";
//Dart
String name1 = 'Dart';? ?或者? ? var name2 = 'dart';都是可以接受的,其中name2進(jìn)行了類(lèi)型推斷。
5、默認(rèn)值
JavaScript:未初始化的變量默認(rèn)值是undefined。
Dart:未初始化的變量默認(rèn)值是null。
注意,數(shù)字在dart語(yǔ)言中也被當(dāng)成對(duì)象,所以即使是帶有數(shù)字類(lèi)型的對(duì)象沒(méi)有給出初始化默認(rèn)值,那么該對(duì)象值就是“null”。
//JavaScript
var name;? ?// ==undefined
//Dart
String name;? // ==null
int a;? ? //? ==null
6、檢查null或零
JavaScript:1或者任何非null對(duì)象的值被視為true。
Dart:只有布爾值為true才被視為true。
// is運(yùn)算符用于判斷一個(gè)變量是不是某個(gè)類(lèi)型的數(shù)據(jù)
// is!則是判斷變量不是某個(gè)類(lèi)型的數(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)算符類(lèi)似于Java中的cast操作,將一個(gè)對(duì)象強(qiáng)制類(lèi)型轉(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的情況下會(huì)阻斷右邊函數(shù)的調(diào)用
var str1 ="hello world";
var str2 =null;
print(str1?.length);// 11
print(str2?.length);// null?
print(str2.length);// 報(bào)錯(cuò)
//??運(yùn)算符在左側(cè)表達(dá)式為null的時(shí)候?yàn)槠湓O(shè)置右邊為默認(rèn)值
print(null??false);//false
print(false??11);//false
print(true??false);//true
7、final和const
如果你絕不想改變一個(gè)變量,使用final或const,不要使用var或其他類(lèi)型,一個(gè)被final修飾的變量只能被賦值一次,一個(gè)被const修飾的變量是一個(gè)編譯時(shí)常量(const常量毫無(wú)疑問(wèn)也是final常量)。可以這么理解:final修飾的變量是不可改變的,而const修飾的表示一個(gè)常量。
注意:實(shí)例變量可以是final的但不能是const的
說(shuō)明:
var count =10;
final Num = count;// final 只能賦值一次
const Num1 =10;// const賦值必須是編譯時(shí)常量
final和const的區(qū)別:
區(qū)別一:final 要求變量只能初始化一次,并不要求賦的值一定是編譯時(shí)常量,可以是常量也可以不是。而 const 要求在聲明時(shí)初始化,并且賦值必需為編譯時(shí)常量。
區(qū)別二:final 是惰性初始化,即在運(yùn)行時(shí)第一次使用前才初始化。而 const 是在編譯時(shí)就確定值了。
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語(yǔ)句的簡(jiǎn)寫(xiě)
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ù)時(shí),你可以以?{type paramName}?或者?{paramName: type}?兩種方式聲明參數(shù),而調(diào)用命名參數(shù)時(shí),需要以?funcName(paramName: paramValue)?的形式調(diào)用
注意:命名參數(shù)被{ }括了起來(lái),類(lèi)似于map的形式,調(diào)用的時(shí)候需要 參數(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ù)
使用中括號(hào)[]括起來(lái)的參數(shù)是函數(shù)的位置參數(shù),代表該參數(shù)可傳可不傳,位置參數(shù)只能放在函數(shù)的參數(shù)列表的最后面,如下代碼所示:
sayHello(String name, int age, [String hobby]) {// 位置參數(shù)可以有多個(gè),比如[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}){// 不能寫(xiě)成: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、類(lèi)
類(lèi)的定義與構(gòu)造方法
Dart中的類(lèi)沒(méi)有訪問(wèn)控制,所以你不需要用private, protected, public等修飾成員變量或成員函數(shù),一個(gè)簡(jiǎn)單的類(lèi)如下代碼所示:
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類(lèi)中有3個(gè)成員變量,一個(gè)構(gòu)造方法和一個(gè)成員方法,看起來(lái)比較奇怪的是Person的構(gòu)造方法,里面?zhèn)魅氲?個(gè)參數(shù)都是this.xxx,而且是沒(méi)有大括號(hào){}包裹的方法體,這種語(yǔ)法是Dart比較獨(dú)特而簡(jiǎn)潔的構(gòu)造方法聲明方式,它等同于下面的代碼:
Person(String name, int age,String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
要調(diào)用Person類(lèi)的成員變量或成員方法,可以用下面的代碼:
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
類(lèi)除了有跟類(lèi)名相同的構(gòu)造方法外,還可以添加命名的構(gòu)造方法,如下代碼所示:
class Point{?
num x, y;?
Point(this.x,this.y);
// 類(lèi)的命名構(gòu)造方法
Point.origin() {??
? x =0;??
? y =0;??
?}
}
main() {
// 調(diào)用Point類(lèi)的命名構(gòu)造方法origin()
var p =new Point.origin();
var p2 =new Point(1,2);
}
Dart中使用extends關(guān)鍵字做類(lèi)的繼承,如果一個(gè)類(lèi)只有命名的構(gòu)造方法,在繼承時(shí)需要注意,如下代碼:
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類(lèi)沒(méi)有默認(rèn)構(gòu)造方法,只有一個(gè)命名構(gòu)造方法fromJson,所以在Man類(lèi)繼承Human類(lèi)時(shí),需要調(diào)用父類(lèi)的fromJson方法做初始化,而且必須使用Man.fromJson(Map data) : super.fromJson(data)這種寫(xiě)法,而不是像Java那樣將super寫(xiě)到花括號(hào)中。
有時(shí)候你僅僅只是在某個(gè)類(lèi)的構(gòu)造方法中,調(diào)用這個(gè)類(lèi)的另一個(gè)構(gòu)造方法,你可以這么寫(xiě):
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);}
類(lèi)的成員方法
一個(gè)類(lèi)的成員方法是一個(gè)函數(shù),為這個(gè)類(lèi)提供某些行為。上面的代碼中已經(jīng)有了一些類(lèi)的成員方法的定義,這些定義方式跟Java很類(lèi)似,你可以為某個(gè)類(lèi)的成員變量提供getter/setter方法,如下代碼:
class Rectangle{
num left, top, width, height;//?
構(gòu)造方法傳入left, top, width, height幾個(gè)參數(shù)
Rectangle(this.left,this.top,this.width,this.height);
// right, bottom兩個(gè)成員變量提供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;
}
抽象類(lèi)和抽象方法
使用abstract修飾一個(gè)類(lèi),則這個(gè)類(lèi)是抽象類(lèi),抽象類(lèi)中可以有抽象方法和非抽象方法,抽象方法沒(méi)有方法體,需要子類(lèi)去實(shí)現(xiàn),如下代碼:
abstract class Doer{
// 抽象方法,沒(méi)有方法體,需要子類(lèi)去實(shí)現(xiàn)
void doSomething();
// 普通的方法
void greet(){?
? print("hello world!");??
}}
class EffectiveDoer extends Doer{
// 實(shí)現(xiàn)了父類(lèi)的抽象方法
void doSomething(){?
?? print("I'm doing something...");?
?}}
運(yùn)算符重載
Dart中有類(lèi)似于C++中的運(yùn)算符重載語(yǔ)法,比如下面的代碼定義了一個(gè)向量類(lèi),重載了向量的+ -運(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
}
枚舉類(lèi)
使用enum關(guān)鍵字定義一個(gè)枚舉類(lèi),這個(gè)語(yǔ)法跟Java類(lèi)似,如下代碼:
enum Color { red, green, blue }
mixins
mixins是一個(gè)重復(fù)使用類(lèi)中代碼的方式,比如下面的代碼:
classA{??
a() {
? ? print("A's a()");??
}
}
classB{?
?b() {? ?
?print("B's b()");??
}
}
// 使用with關(guān)鍵字,表示類(lèi)C是由類(lèi)A和類(lèi)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)成員方法
// 類(lè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對(duì)象表示異步操作的最終完成(或失?。┘捌浣Y(jié)果值
Dart:future來(lái)表示異步操作
12、async和await
async函數(shù)聲明定義了一個(gè)異步函數(shù)。
JavaScript:async函數(shù)返回一個(gè)promise,await運(yùn)算符用來(lái)等待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ù)返回一個(gè)future,函數(shù)的主體是稍后執(zhí)行,await運(yùn)算符用來(lái)等待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);
}