Dart
1.语言简介
(1)Dart是Google发布的一门开源编程语言。Dart是一种面向对象的语言,具有C语言风格的语法,可以选择将它编译成JavaScript。它支持各种编程辅助工具,如:接口,类,集合,泛型和可选类型。
(2)Dart可以广泛用于创建单页面应用程序。单页应用程序仅适用于网站和Web应用程序。单页应用程序可以在网站的不同屏幕之间进行导航,而无需在浏览器中加载不同的网页。一个典型的例子是GMail—当点击收件箱中的邮件时,浏览器会停留在同一个网页上,但JavaScript代码会隐藏收件箱并将邮件正文显示在屏幕上。
(3)谷歌发布了一个特殊的Chromium版本 - Dart VM 。使用Dartium可以在浏览器上进行测试之前,不必将代码编译为JavaScript。
下表是Dart和JavaScript的功能比较。
特征 | Dart | JavaScript |
---|---|---|
类型系统 | 可选,动态 | 弱,动态 |
类 | 单继承 | 原型 |
接口 | 多接口 | 不支持 |
并发 | 支持,隔离 | 支持,使用HTML5网络worker |
2.应用场景
3.Dart 环境安装
(1)Flutter
在编辑器(Android studio / Vs Code)中安装Flutter会直接安装Dart
(2)单独使用Dart
先安装Chocolatey ==》 使用管理员运行powershall ==》执行https://chocolatey.org/install中的安装命令
执行choco install dart-sdk 或者 下载压缩包
添加环境变量path
二.常量,变量,运算符
1.var 变量(和JS的var差不多一样)
var a;
print(a);// null
var定义的变量如果未给初始值则打印出来为null
a = 10;
print(a);
给a再次赋值,a打印结果为10
a = "hello Dart";
print(a);
给a再次赋值,a打印结果为hello Dart
注意:如果先前使用var声明了a,如果再使用var声明a,则会报错 Context: Previous declaration of ‘a’(先前已经声明了a)
2.final (只能赋值一次)
final c = 30;
c = "final 只能赋值一次";
print(c);
final声明变量时只能为它赋值一次,如果再次赋值则会报错 Error: Can’t assign to the final variable ‘c’ (不能赋值给最终变量c)
3.const 常量
使用const声明的必须是编译期常量
注意:const声明的基本数据类型不能改变和Js中一样,但是Js中cosnt声明的变量如果为对象,则是可以改变对象中的属性值的,dart不能,const在dart中声明的常量不可映射,因此无法改变属性值
4.Dart中数据类型
内置数据类型:
数值型-Number
字符串-String
布尔型-Boolean
列表-List
键值对-Map
(Runes Symbols 使用机会不多)
(1)数值型
num
—— int (整型)
—— double (浮点型)
int b = 20;
b = 20.5;
//报错 Error: A value of type 'double' can't be assigned to a variable of type 'int'.
double c = 33.33;
c = 30;
print(c);
注意:
int 声明的变量不可以赋值为浮点型
double 声明的变量可以赋值为整型,打印结果为浮点型
Dart中也会出现精度缺失问题
(2)字符串
使用单引号或者双引号创建字符串
使用三个引号或双引号创建多行字符串
使用r创建原始raw字符串
注意:Dart中字符串只能做+拼接作用,不能与数值型、布尔值等进行隐式转换
(3)dynamic
变量如果为动态,可以随意赋值任何类型、任何值的时候,此变量类型为dynamic
5.运算符
运算符: +、-、*、/、~/(取整)、%
常用属性:isNaN、isEven(是否偶数)、isOdd(是否奇数)
常用方法:abs()(取绝对值)、round()(把数四舍五入为最接近的整数)、floor()(对数进行下舍入)、ceil()(对数进行上舍入)、toInt()(转整型)、toDouble()(转浮点型)
三.字符串
1.运算符
+、*、==、[]
(1)
String name = '李大钊';
print('name:' + name) //name:李大钊
(2)
String name = '李大钊';
print(name * 2) //李大钊李大钊
(3)
String name = '李大钊';
print(name == '李大钊') //true
(4)
String name = '李大钊';
print(name[0]) //李
2.插值表达式
${expression}
int a = 1;
int b = 2;
print('a + b = ${a + b}');
3.字符串操作
常用属性:length、isEmpty、isNotEmpty
(1)str.length 可以获取到字符串的长度(这个字符串中单个字符的数量)
(2)str.isEmpty 是否为空
(3)str.isNotEmpty 是否不为空
(4)int.parse(str) 字符串转int(字符串中不能是小数)
(5)double.parse(str) 字符串转double
(6)num.toString() 转字符串
(7)num.toStringAsFixed(n) 保留精度 n为小数点后位数 (会四舍五入)
字符串切割
(8)substring 用于提取字符串中介于两个指定下标之间的字符
str.substring(start,end);
从str的第start个位置(包含这个位置)开始,截取到第end个位置(不包含这个位置)
str.substring(index);
从str的第index个位置开始,截取到字符串的末尾
(9)split 将字符串以指定的字符分割成一个数组
判断字符串是否包含或者以xxx开始 / 结束
(10)startsWith(‘xxx’) 判断字符串以xxx开始
startsWith(‘xxx’,n) 判断字符串以xxx开始,从index = n 开始判断
(11)endsWith(‘xxx’) 判断字符串以xxx结束
endsWith(‘xxx’,n) 判断字符串以xxx开始,从index = n 开始判断
(12) contains('xxx) 判断字符串是否包含xxx
contains(‘xxx’,n) 判断字符串是否包含xxx,从index = n 开始判断
字符串替换
(13)replaceAll(‘a’,‘b’) 替换所有符合条件的,将所有a替换为b
(14)replaceFirst(‘a’,‘b’)只替换第一个符合条件的,将第一个a替换为b
(15)replaceRange(start,end,str)范围替换,将start–end的字符串替换为str,含start不含end
(16)indexOf(’xxx‘,index) 获取指定字符串在父级字符串中第一次出现的位置
携带第二个参数则从index等于第二个参数处开始查找
(17)lastIndexOf(’xxx‘,index) 从后往前找 返回第一个符合条件的index
字符串转大小写
(18)toLowerCase 字符串转小写
(19)toUpperCase 字符串转大写
字符串去除空格
(20)trim 去除左右两边空格 trimRight 去除右边空格 trimLeft 去除左边空格
字符串补齐长度
(21)padLeft(length,str)从左边补齐
padRight(length,str)从右边补齐
length:补齐之后字符串的长度
str:指定使用str字符串补齐。默认为''
如果指定长度小于原字符串长度,则返回原字符串
四.List(数组)Js中为Array
1.创建数组
var list1 = [1,2,3];
var list2 = const [1,2,3]; //创建不可变的List
var list3 = new List(3); //构造函数创建List [null, null, null]
在Js中使用构造函数创建数组,如果构造函数中传参,则参数为创建数组的长度,每个数组元素为empty。在Dart中,参数含义一样,只不过每个数组元素为null
2.数组操作
length 获取数组长度
add 从数组尾部添加元素
insert(index,el) 向数组index位置插入元素el
remove 删除数组index位置的元素 或者直接移除元素
clear 清空数组
indexOf 查找目标元素第一次出现的位置
lastIndexOf 查找目标元素最后一次出现的位置
sort 排序 可以传一个排序方法参数
sublist(start,end) 截取数组并返回新的数组
join 以指定的字符连接数组中所有的元素,形成一个新的字符串(数组本身不会发生变化)
followedBy 将自身和参数内list合成一个List
五.Map(键值对)类似于JSON,Object
1.创建数组
var map1 = {'first': 'dart', 'second': 'java'};
var map2 = const{'first': 'dart', 'second': 'java'};; //创建不可变的Map
var map3 = new Map(); //构造函数创建Map {}
2.键值对操作
length 获取键值对长度
isEmpty 是否为空
isNotEmpty 是否不为空
keys 获取键值对的键
values 获取键值对的值
containsKey 返回是否包含某个key
containsValue 返回是否包含某个value
remove 移除键值
forEach 循环
六.条件表达式
1.三目运算符
condition ? express1 :express2
2.??运算符
express1 ?? express2
3.if … else …
4.switch… case…
七.循环语句
1.for…
2.while …
3,do…while
…(与JS其他常用的差不多)
八.方法定义
1.返回类型 方法名 (参数){
方法体
return 返回值(可无返回值)
}
2.可选参数
printPerson1('张三',age:20);//可选参数为Map类型,给可选参数传参时要写参数名
printPerson2('李四',20);//可选参数为List类型,传参需要按参数位置来传参
//正常的参数需要在可选参数之前
printPerson1(String name,{int age, String gender}){
print('name=$name,age=$age,gender=$gender');
}
printPerson2(String name,[int age, String gender]){
print('name=$name,age=$age,gender=$gender');
}
3.默认参数
printPerson3('李四');
printPerson3(String name,{int age = 18, String gender = '男'}){
print('name=$name,age=$age,gender=$gender');//name=李四,age=18,gender=男
}
九.面向对象
1.类与对象
使用关键字class声明一个对象
使用关键字new创建一个对象,new可省略
所有对象都继承于Object类
属性默认会生成getter和setter方法
使用final声明的属性只有getter方法
方法不能被重载
2.类及成员可见性
Dart中的可见性以library(库)为单位
3.计算属性
计算属性的值是通过计算而来,本身不存储值
计算属性赋值,其实是通过计算转换到其他实例变量
class Rectangle {
num width,height;
num get area => width * height;
set area (value) {
width = value / 20;
}
}
4.构造方法
如果没有自定义构造方法,则会有默认的构造方法
如果存在自定义构造方法,则默认的构造方法无效
构造方法不能重载(不能命名一样)
//实例化构造函数
var persion = new Persion('Tom',20);
class Persion {
String name;
int age;
// 构造方法,如果没有自定义构造方法,则会有默认的构造方法
Persion(this.name,this.age);//构造函数的语法糖
}
(1)命名构造方法
使用命名构造方法,可以实现多个构造方法
使用类名.方法的形式实现
class Persion {
String name;
int age;
// 构造方法,如果没有自定义构造方法,则会有默认的构造方法
Persion(this.name,this.age);//构造函数的语法糖
Persion.withName(String name, this.gender){
this.name = name;
}
}
(2)工厂构造方法
工厂构造方法类似于设计模式中的工厂模式
在构造方法前添加关键字factory实现一个工厂构造方法
class Logger {
final String name;
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) {
print(msg);
}
}
void main(List<String> args) {
var map1 = new Logger('name');
map1.log("2");
}
5.初始化列表
初始化列表会在构造方法执行之前执行
使用逗号分隔初始化表达式
初始化列表常用于设置final变量的值
6.静态成员
使用static关键字来实现类级别的变量和函数
静态成员不能访问非静态成员,非静态成员可以访问静态成员
类中的常量需要使用static const声明
void main(List<String> args) {
var page = new Page();
Page.scrollDown();
}
class Page {
static const int maxPage = 10;// 类中的常量需要使用static const声明
static int currentPage = 1;
static void scrollDown () {
currentPage = 1;
print('scrollDown');
}
void scrollUp () {
currentPage++;
print('scrollUp');
}
}
7.对象操作符
void main(List<String> args) {
Persion persion;
persion?.work; // 相当于可选链
}
类型转换 as
(persion as Persion).work();
类型监测 is is!
if(persion is Persion){
persion.work();
}
级链操作 …
var persion = new Persion();
persion..name = 'Tom'
..age = 20
..work();
new Persion()..name = 'Tom'
..age = 20
..work();
8.对象call方法
如果类实现了call方法,则该类的对象可以作为方法使用
var persion = new Persion();
persion.name = 'Tom';
persion.age = 20;
//persion() // 直接会执行call方法
print(persion('Test',30));
class Persion {
String name;
int age;
// void work () {
// print('work');
// }
String call(String name,int age){
print('name is $name.age is $age');
return 'name is $name.age is $age';
}
}
九.继承
使用extends继承一个类
子类会继承父类可见的属性和方法,不会继承构造方法
子类能够复写父类的方法、getter、setter
单继承,多态性
class Student extends Persion {
void study(){
print('Student study...');
}
// 可以复写父级方法
@override // 修饰符说明这个是由父级来的
bool get isAdult => age > 15;
@override
void run(){
print('student run');
}
}
class Persion {
String name;
int age;
String birthday;
bool get isAdult => age > 18;
void run () {
print('persion run...');
}
}
(1)继承中的构造方法
子类的构造方法默认会调用父类的无名无参构造方法
如果父类没有无名无参构造方法,则需要显示调用父类构造方法
在构造方法参数后使用 : 显示调用父类构造方法
(2)构造方法执行顺序
父类的构造方法在子类构造方法体开始执行的位置调用
如果有初始化列表,初始化列表会在父类构造方法之前执行
class Student extends Persion {
int age;
final String gender;
Student(String name,String gender) :gender = gender, super(name);
}
class Persion {
String name;
// Persion(){ // 无名无参
// print('调用父级构造方法');
// }
Persion(this.name);
Persion.withName(this.name);
}
(3)抽象类
抽象类使用 abstract 修饰,不能直接被实例化
抽象方法不用abstract修饰,无实现
抽象类可以没有抽象方法
有抽象方法的类一定得声明为抽象类
void main(List<String> args) {
var person = new Student();
person.run();
}
abstract class Persion {
void run();
}
class Student extends Persion {
@override
void run() {
// TODO: implement run
print('run');
}
}
十.接口
类和接口是统一的,类就是接口
每个类都隐式的定义了一个包含所有实例成员的接口
class Persion {
String name;
int get age => 18;
void run () {
print('run...');
}
}
// 使用implements关键字
class Student implements Persion{
@override
String name;
@override
// TODO: implement age
int get age => throw UnimplementedError();
@override
void run() {
// TODO: implement run
}
}
如果是复用已有类的实现,使用继承
如果只是使用已有类的外在行为,使用接口
(1)Mixins
Mixins类似于多继承,是在多类继承中重用一个类代码的方式
作为Mixin的类不能有显示声明的构造方法
作为Mixin的类只能继承自Object
使用关键字with连接一个或多个Mixin
class A {
void a(){
print('a');
}
}
class B {
void b(){
print('b');
}
}
class Test {}
class C {
void c(){
print('c');
}
}
class D extends A with B, C{
}