一. 重要概念
- 1.所有变量都是引用的对象,而对象都是某个类的实例.数字,函数,null皆为对象. 所有类都继承自Object.
- 2.Dart可以类型推断, 也可以指定类型.
- 3.Dart没有类似于Java的public,protected和private成员访问限定符, 而是采用下划线(_)标识私有.
- 4.Dart中表达式和语句有区别.表达式有值而语句没有值.比如条件表达式 expression condition ? expr1 : expr2 中含有值 expr1 或 expr2。与 if-else 分支语句相比,if-else 分支语句则没有值.
-
- Dart中未初始化的变量,其默认值都是null.
二. 数据类型
1. final和const
const相对于final,更加严格.
- 1.final和const都是声明处赋值, 但是final的赋值和var的赋值是一样的,const的赋值就必须是编译时常量,不是那么随意.
- 2.final的引用对象内的属性是可变的,但是引用对象本身是不可以变的. Dart中const不能更改对象内的属性值;
- 3.声明类成员变量的时候,const的前面必须要有static
2. 内置类型
1.Number类型
Number包含int, double类型;
int整数值;长度不超过 64位,具体取值范围依赖于不同的平台。在 DartVM 上其取值位于 -263 至 263 - 1 之间。编译成 JavaScript 的 Dart 使用 JavaScript 数字,其允许的取值范围在 -253 至 253 - 1 之间。
64位的双精度浮点数字,且符合 IEEE 754 标准。
2.String类型
Dart的字符串是UTF-16编码的字符串序列.
-
- 单引号和双引号都能创建字符串
-
- ${表达式}可以在字符串中插入值, 如果表达式是单个的标识符(比如一个单独的变量),就能省略{}
-
- +号可以拼接字符串, 三引号或者三个双引号能创建多行字符串
-
- 字符串前加r就能创建"raw"字符串(字符串不被做处理)
-
- 声明编译时常量的字符串时, 插值表达式需是编译时常量(null,String,Number,Boolean)
3.Boolean类型
Dart中应该显式的判断,不能再用js中比如
var str = '';
if (str) {xxx} else {xxx}
而是应该用if (str.isEmpty) {xxx} else {xxx}
Dart 使用 bool 关键字表示布尔类型,布尔类型只有两个对象 true 和 false,两者都是编译时常量。
4.List类型
类似于JavaScript的数组
- 1.类型被推断后,再次加入新的类型数据,会报错.
- 2.提供了扩展符(...)和null-aware(...?),类似于JavaScript的(...)运算符, null-aware是防止被解构变量为null
- 3.提供了if或者for来构建集合.
var listOfInts = [1, 2, 3];
var listOfStrings = [
'#0',
for (var i in listOfInts) '#$i'
];
var nav = [
'Home',
'Furniture',
'Plants',
if (promoActive) 'Outlet'
];
5.Set类型
set 是一组特定元素的无序集合.也是不允许存在重复值.
声明Set:
// 字面量方式生成
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
// 类型+{}的形式创建Set。
var names = <String>{};
// 声明类型变量的形式创建Set
Set<String> names = {};
6.Map类型
类似于JavaScript的map.
声明Map的2种方式:
// map字面量的方式
var gifs = {
// 键: 值
'first': 'partridge',
'second': 'turtledoves',
'fifth': 'golden rings'
};
// Map构造器的方式
var gifs = Map();
gifs['first'] = 'partridge';
gifts['second'] = 'turtledoves';
gifts['fifth'] = 'golden rings';
7.Runes类型
在 Dart 中,runes 公开了字符串的 Unicode 码位。 从Dart2.6开始,可以使用characters包来访问和操作runes
8. Symbol类型
一个Symbol对象表示一个dart声明的标识符或者运算符.平时写代码用的少,暂略.
三. 函数
1. 函数声明
Dart函数大体类似JavaScript函数; 属于Function类型;所有函数皆有返回值,如不写则会隐式的加上return null;声明方式如下:
-
- 函数返回值可以省略,但Dart是类型化的语言,返回值最好写上,无返回值可写void
-
- 参数前加@required, 则为必须参数
-
- []内为可选参数
-
- 可以用 "=" 号来提供函数的参数默认值.
-
- 匿名函数不同于JavaScript的声明, 省去了function关键字,或者箭头函数的箭头,如下所示
// 具名函数的声明
[返回值] 函数名(type param1 = xxx, @required type param2, [type param3, type param4...])
{
//函数体
}
// 匿名函数的声明
([[Type] param1[, …]]) {
codeBlock;
};
// 匿名函数例子
var list = ['apples', 'bananas', 'oranges'];
list.forEach((item) {
print('${list.indexOf(item)}: $item');
});
2.词法作用域
Dart是词法作用域,变量的作用域是固定的, 即在编写代码的时候, 变量的作用域就确定了.
3.闭包
闭包就是对一个函数对象,调用函数对象并未在其词法作用域内,但依然可以访问到函数对象词法作用域内的变量.
Function makeAdd(int n2) {
return (int n) => n2 + n;
}
void main() {
Function func1 = makeAdd(2);
Function func2 = makeAdd(3);
print(func1(4));// 6
print(func2(8));// 11
}
四.运算符
1.算数运算符
| 那算符 | 备注 | 示例 |
|---|---|---|
| ~/ | 取余整数 | print(5 ~/ 2);//结果为2 |
| is | 类型判断 | var p1 = '123123';print(p1 is String); // 结果为true |
| is! | 类型判断 | 同is相反 |
| as | 强制类型转化 | var p1 = '123123';String p2 = p1 as String;print(p2 is String);// 结果为true |
| ??= | 当被赋值变量为null时才赋值 |
五.控制流程语句
1. try catch finally
和 Java 有所不同, Dart 中的所有异常是非检查异常(运行时异常,编译阶段不会检查异常)。 方法不会声明它们抛出的异常, 也不要求捕获任何异常。 Dart 提供了 Exception 和 Error 类型, 以及一些子类型。 当然也可以定义自己的异常类型。 但是,此外 Dart 程序可以抛出任何非 null 对象, 不仅限 Exception 和 Error 对象。
catch可以指定类型,捕捉特定类型的错误,不指定类型的,捕捉所有类型的错误.
try {
breedMoreLlamas();
} on OutOfLlamasException {
// 一个特殊的异常
buyMoreLlamas();
} on Exception catch (e) {
// 其他任何异常
print('Unknown exception: $e');
} catch (e) {
// 没有指定的类型,处理所有异常
print('Something really unknown: $e');
}
六.类
- Dart是一种基于类和mixin继承机制的面向对象语言;
- 所有的类都继承自Object;
- 基于mixin继承机制, 每个类都只有一个超类
1. 构造函数声明
(1) 默认构造函数.类中没有声明构造函数的情况下, Dart默认提供一个默认的构造函数, 此默认构造函数无参且会默认调用父类无参构造函数; 但是,如果类中存在任何一个构造函数,Dart都不在提供默认的构造函数.
// 此类会存在一个默认的无参构造函数
class Point {
num x, y;
}
// 此类不会存在默认构造函数, 因为类中存在命名的构造函数
class Point {
num x, y;
Point.origin() {
x = 0;
y = 0;
}
}
(2) 命名构造函数.一个类可以实现多个命名的构造函数.有利于清晰的表达用途; 子类不能继承父类的构造方法;
// Point.origin即为命名的构造函数
class Point {
num x, y;
Point.origin() {
x = 0;
y = 0;
}
}
(3) 调用父类命名构造函数.在当前类构造函数:号之后,函数体之前,调用父类的构造函数
:号右侧无法访问this
执行顺序如下:
- 1.初始化参数列表
- 2.父类构造函数
- 3.子类构造函数
// 父类
class Person {
String firstName;
Person.fromJson(Map data) {
print('in Person');
this.firstName = data['firstName'];
}
}
// 子类
class Employee extends Person {
String s;
// 父类不存在默认构造函数,所以,必须显式的调用父类的命名构造函数
Employee.fromJson(Map data, String s) : super.fromJson(data) {
print('in Employee');
this.s = s;
}
}
void main(List<String> arguments) {
// 先输出in Person, 后输出in Employee
Employee e = new Employee.fromJson({'firstName': 'shen'}, '哈哈哈');
}
(5)初始化参数列表
方式一: 使用语法糖
class Point {
num x, y;
// 次处的this.x和this.y就相当于在构造函数体内进行赋值操作
Point(this.x, this.y);
}
方式二: 在:号右侧初始化(:号右侧无法访问this)
class Point {
num x, y;
Point(this.x, this.y);
// 为x和y赋值操作
Point.fromJson(Map<String, num> json)
: x = json['x'],
y = json['y'] {
print('In Point.fromJson(): ($x, $y)');
}
}
(6) 重定向构造函数
有时构造函数的唯一目的是重定向到同一个类中的另一个构造函数。 重定向构造函数的函数体为空, 构造函数的调用在冒号 (:) 之后。
class Point {
num x, y;
// 类的主构造函数。
Point(this.x, this.y);
// 指向主构造函数
Point.alongXAxis(num x) : this(x, 0);
}
(7) 常量构造函数
如果该类生成的对象是固定不变的, 那么就可以把这些对象定义为编译时常量。
class ImmutablePoint {
static final ImmutablePoint origin =
const ImmutablePoint(0, 0);
final num x, y;
const ImmutablePoint(this.x, this.y);
}
(8) 工厂构造函数
工厂构造函数无法访问 this。
当执行构造函数并不总是创建这个类的一个新实例时,则使用 factory 关键字。
class Logger {
final String name;
bool mute = false;
// 从命名的 _ 可以知,
// _cache 是私有属性。
static final Map<String, Logger> _cache =
<String, Logger>{};
factory Logger(String name) {
if (_cache.containsKey(name)) {
return _cache[name];
} else {
final logger = Logger._internal(name);
_cache[name] = logger;
return logger;
}
}
Logger._internal(this.name);
void log(String msg) {
if (!mute) print(msg);
}
}
2. 构造函数使用
在 Dart 2 中 new 关键字变成了可选的。
通过构造函数创建对象. 构造函数的名字可以是类名(className)或者类名标识符(className.identifier).
class Person {
String firstName;
Person.fromJson(Map data) {
print('in Person');
}
}
// 使用类名创建类对象
var p1 = Point(2, 2);
// 使用类标识符创建类对象
var p2 = Point.fromJson({'x': 1, 'y': 2});
3. 获取对象类型
使用对象的属性runtimeType可以在运行时返回对象的类型
/* ----------示例一 ------------------*/
var emp = new Employee.fromJson({});
print('The type of emp is ${emp.runtimeType}'); // 返回Employee
/* ----------示例二 ------------------*/
var emp = new Employee.fromJson({});
emp.firstName = 'Bob';
print('The type of emp is ${emp.firstName.runtimeType}'); // 返回String
4. 类实例变量
类实例变量默认值为null, 非final的实例变量为默认声明隐式的getter和setter.
类实例变量如果已经在声明处赋值, 则赋值会在构造函数执行之前执行.
class Person {
String firstName = 'shen';
Person.fromJson(Map data) {
// 对属性的赋值会在构造函数执行之前执行
print(this.firstName);
print('in Person');
}
}
main() {
var emp = new Person.fromJson({});
}
5. 方法
方法是为对象提供行为的函数.
(1) 方法
class Point {
num x, y;
Point(this.x, this.y);
num distanceTo(Point other) {
var dx = x - other.x;
var dy = y - other.y;
return (dx * dx + dy * dy);
}
}
void main() {
Point p1 = new Point(1,2);
Point p2 = new Point(2,4);
print(p1.distanceTo(p2));
}
(2) set和get
声明get和set, 不能重复声明已经存在的属性.这个不同于java等语言
由get和set可以做计算属性的效果.
class Point {
num x, y;
Point(this.x, this.y);
// 显式声明属性n的get方法
num get n => x + 10;
// 显式声明属性n的set方法
set n (num value) {
this.y += 100;
}
}
void main() {
Point p1 = new Point(1,2);
print(p1.n);
p1.n = 200;
print(p1.y);
}