专注于WEB前端开发, 追求更好的用户体验, 更好的开发体验 [长沙前端QQ群:234746733]

Dart 语言介绍

把年初对dart/flutter/RN的分享内容慢慢整理下, 希望对刚入门app开发的同学有用.

Dart是什么?

  • Google造的轮子(弥补js的不足)
  • 落: JavaScript(NodeJS/React/RN/Vue等)崛起
  • 起: Google内部孵化了Sky项目(用Dart编写, 后改名Flutter)
  • Google的未来操作系统Fuchsia中,Dart被指定为官方的开发语言
  • 2018年8月正式发布 Dart 2.0
  • Dart可运行在有自己的VM上(DartVM), 也可以编译成Native Code运行在硬件上(Flutter将代码编译成Native Code).

Dart特性

  • 单线程异步事件模型(single-threaded), similar to NodeJS
  • 强类型语言,支持弱类型写法(2.0开始)
  • DartVM的性能比肩Java7的JVM(作者Lars Bak负责了 HotSpot JVM/V8 engine)
  • 面向对象的,一切数据类型派生自 Object
  • 独特的隔离区(Isolate), 可以实现多线程 (与线程类似但不共享内存)
  • Future、Stream模型(Dart:async库的核心API, 异步编程)
  • 跨平台: 前端、后端、移动

Dart的方向 (Flutter: iOS,Android,Fuchsia,web,desktop)

  • Native (原生, 移动app/桌面程序)
  • server-side(Server端, 异步高并发/Isolate多线程)
  • client-side(前端, 利用dart2js编译成js)

Dart 语法

main() { // 应用的入口, 程序开始执行的地方
 print("Hello, world!");  // 打印信息
}

变量与常量

var n1 = 9527; // 没声明类型, 编译的时候根据值推断类型(var后面不能带类型 )
String n2 = 'Bob'; // 显示声明字符串类型
int count; // 未初始化变量的初始值为null(数字类型也是null)
// * 如果对象类型不确定, 使用Object或dynamic关键字
Object n3 = true; // 任何类型对象
dynamic 4 = 'Alice'; // Dart类型系统之外的类型 或 明确地声明运行时动态处理的变量
print('$n3 $4 ${n3 is bool} ${4 is String}'); // 字符连接 无需+号拼接,也无需做类型转换

// * 如果变量值不会改变, 使用 final 或 const, 不是var或类型
int func() => 2;  final int n = func();  // 错误: const int n = func();
static const String user = 'Leon'; // 常量如果是类级别的, 使用 static
// const比final更严格, 是编译时常量, 在编译时就已经知道了它的值;
// final只要求变量在初始化后值不变(无法在编译时知道变量的值);

数据类型

// - num (数字). num是数字类型的父类, 有两个子类 int 和 double.
double b = 1.12;
int n = int.parse('10'); // String -> int
1.12543.toStringAsFixed(2); // 输出: 1.13, 会做四舍五入

// - String (字符串). 可以使用单引号或双引号来创建字符串.
String s = 1.toString(); // int -> String
String s = 'aBc'.toUpperCase(); // ABC

// - bool (布尔). 强bool类型检查, 只有bool类型的值是true, 才被认为是true.

// - List (列表). 数组是List对象
List arr = [1, 2]; // or: List arr = List();
List.from([1, 2, 3]); // 创建List
arr.add(3); // 1, 2, 3
arr.addAll([4, 5]); // 添加多个元素, 1,2,3,4,5
arr.addFirst(), arr.addLast() // 在开头或末尾添加元素
print(arr.length); // List长度
print(arr[1]); // 根据索引获取
arr.first, arr.last; // 获取 第1个, 或最后1个
arr.forEach((o) => print(o)); // 遍历
arr.map((o) => '$o').toList(); // 遍历并返回新List
arr.every((o) => o >= 1); // 每个item都满足条件
arr.any((o) => o >= 1); // 是否存在满足条件的item(至少1个)
arr.where((o) => o > 1).toList(); // 返回满足条件的元素集合 (filter)
arr.firstWhere((o) => o > 3, orElse: () => null); // 返回第1个满足条件的元素,或null (find)
arr.contains(2); // 是否包含item
arr.removeFirst(), arr.removeLast() // 删除 第1个, 或最后1个
arr.remove(4), arr.removeAt(1); // 根据值或索引 删除元素
arr.removeWhere((n) => n > 6); // 根据指定条件 删除元素
arr.removeRange(start, end); // 删除指定范围元素, 含头不含尾
arr.join(', '); // 数组拼接成字符
print(arr.isEmpty); // 是否空, 非空: arr.isNotEmpty

// - Map (映射). key和value的对象
Map m = <dynamic, dynamic>{'1': 'A', '2': null}; // 使用<...> 的方式来定义泛型
m[1] = '1'; // {1: A, 2: null, 1: 1}
m.addAll({'2': 2}); // {1: A, 2: 2, 1: 1}, merge,类似js的Object.assign
m.forEach((key, value) => print('$key, $value')); // 遍历
print(m.containsKey(1)); // 检索Map是否含有某Key
print(m.containsValue(2)); // 检索Map是否含有某Value
m.remove('1'); // 删除某个键
m.putIfAbsent('2', () => "1"); // key在map中不存在时, 设置值
m.clear(); // 清空Map
print(m.length); // 键-值对的数量
print(Map.fromIterable([ // List转Map(Map的key和value由List的元素计算)
  {'id': 1, 'val': '1'}, {'id': 2, 'val': '2'},
], key: (o) => o.id, value: (o) => o)); // {1: {id: 1, val: 1}, 2: {id: 2, val: 2}}

// - Set (集合). 元素没有顺序且不能重复的集合, 不能通过索引获取值
var s = Set();
// s.length, s.add('b'), s.addAll([1, 2]), s.remove('b') // 方法类似List
// Set插入和删除不会引起元素位置改变, 而List会引起位置改变;

运算符

&& # 逻辑与
|| # 逻辑或
!expr # 逻辑非
expr1 ? expr2 : expr3 # 条件表达式
is # 当对象是相应类型时返回 true (obj is Object)
is! # 当对象不是相应类型时返回 true
as # 类型转换, 把1个对象转换为特定类型
.. # 级联/串联(cascade), 对1个对象的成员进行多个操作
   querySelector('#button') // 获取1个对象
     ..text = 'Confirm'   // 调用他的成员
     ..onClick.listen((e) => window.alert('Confirmed!'));
   相当于:
   var button = querySelector('#confirm');
   button.text = 'Confirm';
   button.onClick.listen((e) => window.alert('Confirmed!'));
   // 当回值是void时不能构建级联

流程控制语句(Control flow statements)

if...else
for( var i = 0, j = 1; i <= j; i++ ) {}
for (var x in obj) {}
[].forEach((c) => print(c));
{}.forEach((k,v) => print('${k}: ${v}'));
while and do-while
break and continue
switch...case

异常(Exceptions)

// throw, try...catch, finally
try {
   try { // try..catch
     // throw FormatException('error'); // 抛出异常: 固定类型
     throw 'error'; // 抛出异常: 任意类型
   } catch (e) {
     print("tryCatch1: $e");
     rethrow; // 是否允许异常继续传播
   }
} on FormatException { // 通过 on 指定需要捕获的具体异常类型
 print('FormatException err');
} catch (e) { // 捕获任意类型异常
 print('tryCatch2: $e');
} finally { // finally, 无论异常是否发生都执行
 print('finally');
}

函数(Function)

// 特殊,必要,顶级的函数, 作为应用程序的入口
main(){} // 应用开始执行的地方

void printNumber(num x) { // 声明了参数和返回值的类型
 print('The number is $x');
}
// 函数只包含一条语句, 可使用箭头符号=>简写
printNumber(num x) => print('The number is $x');

// 可选的命名参数, 用{}标记 (可选: msg, from; 用 :或= 声明默认值)
say1(String to, {msg = '', from = null}) => print('to: $to, msg: $msg, from: $from');
say1('Alice', from: 'Bob'); // to: Alice, msg: , from: Bob
// 可选的位置参数, 用[]标记 (可选: msg, from; 用 = 声明默认值)
say2(String to, [String msg = '', from = null]) => print('to: $to, msg: $msg, from: $from');
say2('Alice', 'Howdy'); // to: Alice, msg: Howdy, from: null

// 匿名函数  (forEach调用了一个匿名函数)
[1, 2, 3].forEach((item) => print('$item'));
// 所有函数都返回一个值, 如果没有指定返回值, 则隐式return null
foo() {}; print(foo() == null);

类(Classes)

// 使用extends创建子类, 使用super引用父类, 使用@override标记重写, 使用.调用实例的变量或方法.
class User { // 类
 String name, gender; // 定义属性
 // 定义 构造函数(Constructors) (与类同名)
 User(this.name, this.gender); // 推荐的写法(直接赋值, 简化了下面的代码):
 // Point(String name, String gender) { // 不推荐的写法
 //   this.name = name; this.gender = gender;
 // }

 User.fromJson(Map json) // 命名构造函数(Named constructor)
   : name = json['name'], gender = json['gender']; // 初始化列表(用冒号开始, 逗号分隔)
 // 初始化列表常用于初始化实例参数, 也可调用父类的构造函数: `..., super(xx)`
 // 默认, 子类的构造函数会自动调用父类的`无名无参的默认构造函数`, 但是如果提供了初始化参数列表, 则初始化参数列表会提前执行,
 // 执行顺序变为: 初始化参数列表->父类无名构造函数->子类无名构造函数.
 // 如果超类中没有无名无参构造函数, 那么就需要手动调用了, 调用方法: ..., super(xx)

 _privateMethod() => print('表示私有: 属性和方法名以`_`开头');
 static staticMethod() => print('静态方法, 无法通过实例访问'); // User.staticMethod()
}
// * 构造函数(包括 命名构造函数)不能继承

class Vip extends User { // 继承
 // 使用冒号(:)分隔 子类构造函数 和 调用父类构造函数的代码
 Vip(String name, gender): super(name, gender); // 通过super调用父类的构造函数
 Vip.male(String name): this(name, 'male'); // 通过this调用同一类中的其他构造函数
 @override // 重写
 log() => print('${name}, ${this.runtimeType}'); // runtimeType获取对象的类型
}

User b = User('Bob', 'male'); // 创建类的实例 (Dart2使new关键字可选, 无需使用new User())
User a = User.fromJson({ 'name': 'Alice', 'gender': null}); // 调用父类非默认构造函数(命名构造函数)
Vip v = Vip.male('Tom'); // 调用子类非默认构造函数
a.gender ??= 'female'; // 给值为 null 的变量赋值, if-null(`??`)
print(a?.gender); // `?.` 左侧非null, 执行右侧逻辑(method/getter) (避免左边null引发异常)

异步(Asynchrony)

// Future 和 Stream 是 Dart异步处理的核心 API, 无需等待耗时的操作执行完成.
// Future 定义未来要发生的事(类似ES6的 Promises).
// Stream 是流式处理, 比如IO处理, 一般情况每次只会读取一部分数据.
// Future返回一次值, 而Stream将返回多次值.

// 当需要使用一个从Future返回的值时, 有两个选择:
// 使用async和await; 使用Future API;
// 当需要从一个Stream获取值时, 有两个选择:
// 使用async和异步的循环(await for); 使用Stream API;

// Future
Future<String> lookUpVersion() async => '1.0.0'; // async声明异步方法(Future<String> 可省略)
lookUpVersion() // 调用异步方法
 .then((value) => print(value)) // then 注册回调函数
 .catchError((error) => print('Error')); // catchError 异常处理
// Streams (用 await for 等待 stream 中的所有结果)
await for (var request in requestServer) { // requestServer的值是Stram类型
 handleRequest(request);
}
// 很多时候没有必要直接使用 Future 或 Stream API,而是使用 async 和 await 关键字进行异步编程.
// import 'dart:async';
checkVersion() async { // async声明异步方法 (函数内 要使用await, 其方法必须带有async关键字)
 try { // 可以使用 try,catch,finally 来处理使用 await 的异常
   String result = await lookUpVersion(); // 使用 await, 等待执行完后再向下执行
   print(result);
 } catch(e) { print(e); }
 print('DONE');
}
checkVersion();

import library

import 'package:xxx/xxx'; // 导入所有
import 'package:xxx/xxx' show foo, bar; // 仅导入foo, bar
import 'package:xxx/xxx' hide foo; // 导入所有, 并排除foo
import 'package:xxx/xxx' as lib; // 导入时使用别名(解决命名冲突)

Tools

文档

/ 分类: 开发 / TrackBackhttps://xhl.me/archives/dart/trackback标签: dart, flutter

添加新评论 »