Dart和JavaScript對比小結


作為一名web前端來入門dart,新語言和我們熟悉的js有所差異,寫dart的過程中容易受到原有思維的影響,這里把dart和js做一個對比總結,方便查找和熟悉。

 

變量聲明

  1. var 關鍵字

dart和js都支持var關鍵字,使用 var 關鍵詞進行聲明的時候,dart 會自動推斷出 當前變量的類型,如果在變量聲明的時候沒有進行賦值,那么該類型就是動態的,類似於 TS 的 any。在類型推斷上跟 TypeScript 是一致的。

眾所周知,JavaScript 是一門弱類型的語言,而 Dart 是強類型的語言

但dart也支持一些弱類型,Dart 中弱類型有varObject 以及dynamic

大家在學習dart的過程中,可能有疑問:同為弱類型,var, Object 以及dynamic有什么區別?

(1) var 初始可定義, 如果有初始值,那么其類型將會被鎖定,定義之后不可改變類型

(2) Object 動態任意類型,編譯階段檢查類型

(3) dynamic 動態任意類型,編譯階段不檢查類型

var 初始化確定類型后不可更改類型, Object 以及dynamic 可以更改類型

Object 編譯階段檢查類型, 而 dynamic 編譯階段不檢查類型

// 同樣在聲明的時候類型
var a = 'defalut';
Object b = 'defalut';
dynamic c = 'defalut'; // 編譯時不會檢查數據類型

a = 123; 
//出現報錯提示A value of type 'int' can't be assigned to a variable of type 'String'
//Try changing the type of the variable, or casting the right-hand type to 'String'

b = 123;
c = 123;

b.foo(); // 出現報錯提示The method 'foo' isn't defined for the class 'Object'.
// Try correcting the name to the name of an existing method, or defining a method 
// named 'foo'.dart(undefined_method)

c.foo(); // 通過它定義的變量會關閉類型檢查,這段代碼靜態類型檢查不會報錯,但是運行時會crash,
// 因為mic並沒有foo()方法,所以建議大家在編程時不要直接使用dynamic
  1. final 關鍵字  

在學習dart 的過程中,很快就能接觸到 final 關鍵字,大家會發現它和 const 其實很像,都是必須初始化,初始化后都是只讀的,不可變

但此時可能又會發出靈魂疑問:final和const有啥區別?

它們的區別在於,const比final更加嚴格。final只是要求變量在初始化后值不變,但通過final,我們無法在編譯時(運行之前)知道這個變量的值;而const所修飾的是編譯時常量,我們在編譯時就已經知道了它的值。

// 定義常量
final a = 90;
static const b = 90;

final c = new DateTime.now(); // 在編譯時不知道他的值
static const d = new DateTime.now(); // Const variables must be initialized with a
// constant value.Try changing the initializer to be a constant 
  1. 默認值

js中變量的初始值是undefined

var a 
console.log(a) // undefined

在 Dart 中,未初始化的變量擁有一個默認的初始化值: null。即便數字也是如此,因為在 Dart 中一切皆為對象,數字也不例外。要用final的話必須定義一個初始值

var some;  // -> null
bool flag;  // -> null
int number;  // -> null
String str;  // -> null
Object obj;  // -> null
final namic;  // Error: must be initialized
  1. 類型判斷

js用 typeof 來判斷基本類型(字符串(string)、數值(number)、布爾值(boolean)、undefined),用 instanceof 來判斷引用類型(Object對象Array數組Function函數)

var a = 0
var b = '0'
var c
var d = true

var e = {}
var f = []
var g = function(){}

typeof a // number
typeof b // string
typeof c // undefined
typeof d // boolean

e instanceof Object // true
f instanceof Array // true
g instanceof Function // true

dart 用關鍵字 is 來進行類型判斷,返回布爾值,ps: assert 生產環境忽略,debug模式開啟

var a = 123;
print(a is dynamic);  // true
assert(a is Object);  // true
  1. 類型轉換

js除了自動類型轉換之外,還有類型轉換的方法

// json和字符串互相轉換
var obj = {a:'2.2'}
var str = JSON.stringify(obj) // "{"a":"2.2"}"
JSON.parse(str) // {a: "2.2"}
Number(obj.a) // 2.2 // 轉成number類型
parseInt(obj.a) // 2 轉成int類型

在實際項目中,后台接口往往會返回一些結構化數據,如JSON、XML等,可以通過dart:convert中內置的JSON解碼器json.decode() 來進行轉換。

通過json.decode() 將JSON字符串轉為List/Map的方法比較簡單,它沒有外部依賴或其它的設置,對於小項目很方便。但當項目變大時,這種手動編寫序列化邏輯可能變得難以管理且容易出錯,JSON.decode()僅返回一個Map<String, dynamic>,這意味着我們直到運行時才知道值的類型。 通過這種方法,我們失去了大部分靜態類型語言特性:類型安全、自動補全和最重要的編譯時異常。

// 內連序列化JSON 使用 dart:convert手動序列化JSON
// JSON.decode方法來解碼JSON
//一個JSON格式的用戶列表字符串
String jsonStr='[{"name":"Jack"},{"name":"Rose"}]';
//將JSON字符串轉為Dart對象(此處是List)
List items=json.decode(jsonStr);
//輸出第一個用戶的姓名
print(items[0]["name"]);

可以通過引入一個簡單的模型類(Model class)來解決前面提到的問題

這樣,調用代碼現在可以具有類型安全、自動補全字段(name和email)以及編譯時異常。如果我們將拼寫錯誤字段視為int類型而不是String, 那么我們的代碼就不會通過編譯,而不是在運行時崩潰。

官方推薦的json_serializable package包 

操作方法:JSON 轉dart Model 類 

布爾值

 

在js中,自動類型轉換,使用判斷的時候空字符串,0,null,undefined都會被轉換為false

var flag = 1 == '1';
console.log(flag);  // -> true

Dart是強類型語言,不會進行自動類型轉換,在判斷的時候就要注意了

bool flag = 1 == '1';
print(flag);  // -> false
// 檢查是否為空字符串。
var fullName = '';
assert(fullName.isEmpty);
// 檢查是否小於等於零。
var hitPoints = 0;
assert(hitPoints <= 0);
// 檢查是否為 null。
var unicorn;
assert(unicorn == null);
// 檢查是否為 NaN。
var iMeantToDoThis = 0 / 0;
assert(iMeantToDoThis.isNaN);

字符串

 

js

var str = 'string' // 單引號
var str2 = "string2" // 雙引號
var str3 = 'test ' + "string" // 字符串拼接
var str4 = `string3${str2}` // 反引號-變量字符串

str.length // 6 字符串長度
str.charAt(1) // s 返回給定位置的字符
str.charcodeAt(1) // 返回給定位置字符的字符編碼
str[1] //s ie8+

str.concat('a') //stringa 可以接受任意多個參數拼接成新的字符串,但不會改變原字符串
str.slice(0,3) //str 截取字符串
str.substring(3) //ing 截取字符串
str.substr(0,1) //s 截取字符串
str.indexOf('s') // 0 可接受兩個參數,找到返回位置,找不到返回-1
str.lastIndexOf('t') // 1 從數組的末尾開始查找
str.trim() //刪除前置和后綴的空格 返回的是字符串的副本,原始字符串不變

str.toLowerCase() //轉小寫
str.toUpperCase() //轉大寫
str.toLocaleLowerCase() //string 轉小寫,針對地區的方法
str.toLocaleUpperCase() //STRING 轉大寫,針對地區的方法

str.match('s') // ["s", index: 0, input: "string", groups: undefined]
str.search('s') //0 接受一個正則,返回字符串中第一個匹配項的索引,沒有返回-1
str.replace('s','c') //ctring 替換字符串,可正則匹配
str.split() //["string"] 分割字符串,並返回一個數組。

dart

String a = 'string' // 單引號 
String b = "string" // 雙引號 
 // 多行字符串
String c = '''string 
huanhang'''
// 使用前綴 r 創建 raw string,字符串內不會進行轉義
String d = r'haha \n breakLine' // 不換行,輸出haha \n breakLine
// 使用變量$name或${name}都可以,前一種方法的后面不能直接跟字符串,要用空格或者逗號等方式隔開
String name = 'hello';
assert('$name string'); // hello string
assert('${name} string'); // hello string
assert(name.length); // 6 字符串長度
assert(name.isEmpty) // false 判斷是否為空
assert(name.isNotEmpty) // true 是否不為空
assert(name.substring(0, 2)) // he 字符串切割
assert(name.substring(3)) // lo 從指定index至末尾
String e = "a,b,,"; 
List<String> a6 = e.split(",");// 使用,分割,返回的是一個數組,同js [a,b, , ]
// 查找並替換 相當於split 和 join
String f = "a b,c";
String g = f.splitMapJoin(",",//查詢“,”
   onMatch: (Match match) { // 用匹配的值替換
     return "a";
   }, onNonMatch: (String nonMatch) { // 用不匹配的值替換
     return "b";
   });
assert(g);//bab    a b,c  =>   bab
// 字符串判斷
String = 'aabbbcccc';
assert(h.startsWith("aa")); //true startsWith以某某開始
assert(h.startsWith("aa", 3)); //false 從index=3開始判斷
assert(h.endsWith("c")); //true endsWith 以xx結尾
assert(h.contains("ab")); //true contains是否包含
assert(h.contains("ac")); //false
assert(h.contains("ab", 3)); //false 從index=3開始判斷
// 字符串替換
String i = "stringing";
assert(i.replaceAll("st","cc"));// ccringing 替換全部符合條件的
assert(i.replaceFirst("ing", "ss"));//strssing 只替換第一個符合條件的
assert(i.replaceFirst("ing", "dd",5));//stringdd 從index=5開始 替換第一個符合條件的
assert(i.replaceRange(0, 3, "z"));// zinging 范圍替換 從0-3 含0不含3
assert(i.replaceAllMapped("i", (Match match){//stryngyng 用方法返回值替換指定的字符串
  return "y";
}));
assert(i.replaceFirstMapped("i", (Match match){
  return "333";
},5)); //string333ng 從index=5開始 用方法返回值替換指定的字符串
// 字符串查找
Sting j = 'hello'
assert(j.indexOf('l')); // 2 從前往后找 返回第一個符合條件的index
assert(j.lastIndexOf('l')); // 3 從后往前找 返回第一個符合條件的index
// 轉換為大小寫
Stinrg k = 'aaBBcC'
assert(k.toLowerCase()); // aabbcc
assert(k.toUpperCase()); // AABBCC  
// 去除空格
String l = " aab bcc ";
assert(l.trim()); //aabbcc 去除左右空格
assert(l.trimLeft()); //aabbcc 去除左邊空格
assert(l.trimRight()); // aabbcc去除右邊空格
// 補齊長度 剩余位使用指定字符串替換
String j = "111";
assert(j.padLeft(6));// 111 剩余3個位 默認使用""補齊
assert(j.padRight(6,"c")); //111ccc 剩余3個位 指定使用"c"
assert(j.padRight(6,"dd")); //111dddddd 剩余3個位 每個位指定使用"dd" 替換后總長度不是6
assert(j.padLeft(2,"e"));//111 如果指定長度小於原字符串長度 返回原字符串

對象

 

js

var gifts = {
  'first': 'partridge',
  'second': 'turtledoves'
};
gifts.first = 'hhh'
// Object.keys(obj) 返回對象的key組成的數組
// Object.values(obj) 返回對象的value組成的數組
// Object.assign() 可以將源對象復制到目標對象中
// Object.entries(obj) 返回對象的key和value組成的數組
// obj.hasOwnProperty() hasOwnProperty 方法判斷對象中屬性是否存在

dart

var gifts = {
  'first': 'partridge',
  'second': 'turtledoves'
};
var gifts = Map();
gifts['first'] = 'partridge';
gifts['second'] = 'turtledoves';

數組

 

js

var list = [1, 2, 3, 4, 5];
var list1 = [1, 2, 3];
var list2 = [4, 5];

console.log(list.length) // 3
list1.concat(list2) // [1, 2, 3, 4, 5] 連接兩個或更多的數組,並返回結果。
list.every(i=>i>3) // false 檢測數值元素的每個元素是否都符合條件。
list.some(i=>i>3) // true 檢測數值元素是否有符合條件的值
list.filter(i=>i>3)    // [4, 5] 檢測數值元素,並返回符合條件所有元素的數組。
list.find(i=>i=3) // 1 返回符合傳入測試(函數)條件的數組元素。
list.forEach() // 遍歷數組
list.join('') // 12345 把數組的所有元素放入一個字符串。
list.map(i=>i+1) // [2, 3, 4, 5, 6] 通過指定函數處理數組的每個元素,並返回處理后的數組。
list.pop() // 5 刪除數組的最后一個元素並返回刪除的元素。
list.push(8) // 5 向數組的末尾添加一個或更多元素,並返回新的長度。
list.shift() // 1 刪除並返回數組的第一個元素。
list.sort() // 排序
list.toString() // 1,2,3,4,5 把數組轉換為字符串,並返回結果。
list.unshift(8) // [8, 1, 2, 3, 4, 5, 6] 向數組的開頭添加一個或更多元素,並返回新的長度。
list.reduce((curr, next) => curr + next); // 15 數組相加的總和

dart

var list = [1, 2, 3];
assert(list.length == 3);
assert(list[1] == 2);

list[1] = 1;
assert(list[1] == 1);

// 同js
list.forEach((i) => print(i)); // 遍歷數組
list.map(i=>i+1) // [2, 3, 4]
list.sort((num1, num2) => num1 - num2); // 排序
list.every(i=>i<5) // true 用法同上
list.reduce((curr, next) => curr + next); // 15 數組相加的總和

list.fold(2,(curr, next) => curr + next);// 17 用法同reduce,有一個初始值
list.contains(5) // false 用於判斷數組是否包含某個元素
list.where((i) => i > 2); // [3] 返回數組中滿足給定條件的元素集合
// firstWhere() 返回數組中滿足給定條件的第一個元素
list.firstWhere((i) => i > 2, orElse: () => null); // 3
// singleWhere() 返回數組中滿足給定條件的唯一一個元素,若有多個元素滿足條件會拋出異常
list.singleWhere((i) => i < 2, orElse: () => null);
List arr = [1, 3, 5, 2, 7, 9];
arr.take(3).toList() // [1, 3, 5] take(n) 從數組里取 n 個元素
arr.skip(4).toList() // [7, 9] skip(n) 跳過數組中的 n 個元素
arr.take(3).skip(2).take(1).toList() // [5]
var clonedArr = List.from(list); // [1, 2, 3] from 克隆一個數組
print(clonedArr);
var arr1 = [[2, 5], [7], [11, 12]];
arr1.expand((item) => item).toList(); // [2, 5, 7, 11, 12]
list.expand((item) => [item * 8]).toList();// [8, 16, 24]
// 當對每一項進行計算時類似於 map() [8, 16, 24]
list.map((item) => item * 8).toList();
list.add(10); // [1,2,3,10] 向數組中添加元素
list.addAll([15, 21]); // [1,2,3,15,21] 向數組中添加另一個數組的所有元素

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM