工作上的需要,被迫上线学习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(); // 这是一种家畜