data-type.md 15.2 KB
Newer Older
D
DCloud_LXH 已提交
1 2 3 4
## 数据类型@data-type

### 布尔值(Boolean)

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
5
布尔是简单的基础类型,只有2个值分别是:`true``false`。在全平台没有差异。
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
6 7 8 9 10

```ts
let a:boolean = true
let b = false
```
D
DCloud_LXH 已提交
11 12 13

### 数字(Number)

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
14
在web中,数字不区分整型和浮点。但在kotlin和swift中,数字需要是一个确定类型,比如Int、Float、Double,没有泛数字。
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
15

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
16
UTS 在iOS和Android平台上新增了 number 类型,拉齐了web端的实现,方便开发者写全端兼容代码。
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
17

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
18
number是一个泛数字类型,包括整数或浮点数,包括正数负数。例如: 正整数 `42` 或者 浮点数 `3.14159` 或者 负数 `-1`
D
DCloud_LXH 已提交
19 20

```ts
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
21
// 以下都是number类型
D
DCloud_LXH 已提交
22
let a:number = 42
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
23 24 25
let b:number = 3.14159
let c = 42
let d = 3.14159
D
DCloud_LXH 已提交
26 27
```

DCloud-yyl's avatar
DCloud-yyl 已提交
28
注意:  
DCloud-yyl's avatar
DCloud-yyl 已提交
29 30
目前版本使用数字字面量申明变量没有指定类型会按平台语言自动推导为相应的类型,如 let c = 42,编译为 kotlin 和 swift 时自动推导为 Int 类型。  
新版本使用数字字面量声明变量将会调整默认为 number 类型,即书写的字面量如果没有明确指定类型会自动识别为 number,要声明平台语言的数据类型变量,需明确指定类型,如 let c:Int = 42。  
杜庆泉's avatar
杜庆泉 已提交
31

DCloud-yyl's avatar
DCloud-yyl 已提交
32
除了 number 类型,UTS 在 Android 和 iOS 设备上,也可以使用 kotlin 和 swift 的专用数字类型:
杜庆泉's avatar
杜庆泉 已提交
33

D
DCloud_LXH 已提交
34 35
#### Kotlin 特有的数字类型 @Kotlin

杜庆泉's avatar
杜庆泉 已提交
36 37 38 39
kotlin 本身支持下列数据类型 

|类型名称|长度  |最小值       |最大值          |描述|
|:--     |:---  |:---         |:---           |:-- |
杜庆泉's avatar
杜庆泉 已提交
40 41 42 43 44 45 46 47
|Byte    |8bit  |-128         |127            |整型|
|UByte   |8bit  |0            |255            |整型|
|Short   |16bit |-32768       |32767          |整型|
|UShort  |16bit |0            |65535          |整型|
|Int     |32bit |-2147483648  |2147483647     |整型|
|UInt    |32bit |0            |4294967295     |整型|
|Long    |64bit |-9223372036854775808 |9223372036854775807     |整型|
|ULong   |64bit |0            |9223372036854775807 * 2 + 1     |整型|
杜庆泉's avatar
杜庆泉 已提交
48 49
|Float   |32bit |1.4E-45F     |3.4028235E38F                   |[浮点型](https://kotlinlang.org/docs/numbers.html#floating-point-types)|
|Double  |64bit |4.9E-324     | 1.7976931348623157E308         |[浮点型](https://kotlinlang.org/docs/numbers.html#floating-point-types)|
杜庆泉's avatar
杜庆泉 已提交
50 51


杜庆泉's avatar
杜庆泉 已提交
52
**kotlin平台数字类型使用实践**
杜庆泉's avatar
杜庆泉 已提交
53

杜庆泉's avatar
杜庆泉 已提交
54
1. 在kotlin平台 `Number`是一个抽象类,编译时会自动选择合适的数据类型来填充,因此大多数场景下,开发者都应该使用 字面量(即Number类型),可以降低心智负担
杜庆泉's avatar
杜庆泉 已提交
55
2. 基本数据类型会有jvm编译魔法加持,在涉及大量科学运算的情况下,计算速度和内存占用会有优化。kotlin 会把  Int / Double 等来非空类型编译为 基本数据类型,Int? / Double? 等可为空的类型编译为 Integer等包装类型,享受不到编译优化加持。如果涉及大量运算,建议开发者不要使用 Number、Int? ,要明确使用 Int等类型 [详情](https://kotlinlang.org/docs/numbers.html#numbers-representation-on-the-jvm)
杜庆泉's avatar
杜庆泉 已提交
56

杜庆泉's avatar
杜庆泉 已提交
57
3. 在 kotlin 和 swift 中,有些系统API或三方SDK的入参或返回值的类型,强制约定了平台特有数字类型,此时无法使用number,需要使用下面列出方法进行转换
杜庆泉's avatar
杜庆泉 已提交
58

D
DCloud_LXH 已提交
59

杜庆泉's avatar
杜庆泉 已提交
60
所有的Number 都支持下列方法进行转换(部分类库API使用java编写,其要求的java类型与下列kotlin类型完全一致,可以直接使用):
杜庆泉's avatar
杜庆泉 已提交
61

杜庆泉's avatar
杜庆泉 已提交
62

杜庆泉's avatar
杜庆泉 已提交
63 64 65 66 67 68 69 70 71 72 73 74 75 76
```
toByte(): Byte

toShort(): Short

toInt(): Int

toLong(): Long

toFloat(): Float

toDouble(): Double
```

杜庆泉's avatar
杜庆泉 已提交
77
另外Number还具备下列函数进行整型的无符号转换,这部分API 在jvm上没有对应的原始数据类型,主要的使用场景是 色值处理等专业计算场景的`多平台拉齐`
杜庆泉's avatar
杜庆泉 已提交
78

杜庆泉's avatar
杜庆泉 已提交
79 80 81 82 83 84 85 86 87 88
```
toUByte(): UByte

toUShort(): UShort

toUInt(): UInt

toULong(): ULong

```
杜庆泉's avatar
杜庆泉 已提交
89 90


D
DCloud_LXH 已提交
91 92 93 94 95 96
#### Swift 特有的数字类型 @Swift

- Int, UInt, Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64
- Float, Float16, Float32, Float64
- Double

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
97 98 99
**特有数字类型的使用场景**

大多数场景下,开发者使用 字面量(即Number类型)就可以满足需要,但是也有需要特有数字类型的场景。
D
DCloud_LXH 已提交
100

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
101 102
1. 在 kotlin 和 swift 中,有些系统API或三方SDK的入参或返回值的类型,强制约定了平台特有数字类型,此时无法使用number。
2. number 作为泛数字,性能还是弱于Int。在普通计算中无法体现出差异,但在千万次运算后,累计会产生毫秒级速度差异。
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
103 104 105 106

当需要特有数字类型时,UTS中可以直接定义<!--,也可以通过number类型转换为特有数字类型。-->

可以使用下面的方法,虽然可能会被编辑器报语法错误(后续HBuilderX会修复这类误报),但编译到 kotlin 和 swift 时是可用的。
D
DCloud_LXH 已提交
107 108

- 声明特定的平台数字类型
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
109
 > 目前这些特有数字类型,声明类型时,与 number 不同的是,均为首字母大写
D
DCloud_LXH 已提交
110 111 112 113 114 115 116 117

```ts

let a:Int = 3 //注意 Int 是首字母大写
let b:Int = 4
let c:Double  = a * 1.0 / b
```

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
118 119
* 注意这些特有数字类型不能在web端和小程序端使用,如工程需兼容非App端,要把这些代码放入条件编译中;
* iOS和Android都有的类型,比如Int,编译后可跨2个平台;但如果使用了某平台专有的数字类型,比如swift的Int8,则此代码不能编译到Android,工程如需支持Android,则把这些代码写在条件编译中。
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
120

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
121
这些特有类型定义后,可以使用kotlin和swift为其提供的各种方法,具体参考kotlin和swift的文档。
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
122

D
DCloud_LXH 已提交
123 124 125 126 127 128 129 130 131
- 在 kotlin(app-android) 下转换特定的平台数字类型
```ts
let a:Int = 3
a.toFloat() // 转换为 Float 类型,后续也将支持 new Float(a) 方式转换
a.toDouble() // 转换为 Double 类型,后续也将支持 new Double(a) 方式转换
```

- 在 swift(app-ios) 下转换特定的平台数字类型
```ts
lizhongyi_'s avatar
lizhongyi_ 已提交
132 133 134 135 136 137
// number转成特定类型
let num = 2
num.toInt() //将number 变量 num 转换为 Int 类型
num.toFloat() //将number 变量 num 转换为 float 类型
num.toInt64() // 将number 变量 num 转换为 Int64 类型

lizhongyi_'s avatar
lizhongyi_ 已提交
138 139 140 141
// 特定类型转成number
let f: Float = 5.0
let n = Number(f)

lizhongyi_'s avatar
lizhongyi_ 已提交
142
// 特定类型转成其他的特定类型
D
DCloud_LXH 已提交
143 144 145
let a:Int = 3
let b = new Double(a) // 将整型变量 a 转换为 Double 类型
```
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
146 147 148 149

<!-- #### number和特有数字类型互转 -->

#### 边界情况说明:
D
DCloud_LXH 已提交
150 151 152 153 154 155

- 在不同平台上,数值的范围限制不同,超出限制会导致相应的错误或异常
  * 编译至 JavaScript 平台时,最大值为 1.7976931348623157e+308,最小值为 -1.7976931348623157e+308,超出限制会返回 `Infinity``-Infinity`
  * 编译至 Kotlin 平台时,最大值为 9223372036854775807,最小值为 -9223372036854775808,超出限制会报错:`The value is out of range‌`
  * 编译至 Swift 平台时,最大值 9223372036854775807,最小值 -9223372036854775808,超出限制会报错:`integer literal overflows when stored into Int`

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
156 157 158
#### 更多API
number内置对象还有一些API,[详见](buildin-object-api/number.md)

D
DCloud_LXH 已提交
159 160 161 162
### 字符串(String) @String

字符串是一串表示文本值的字符序列,例如:`"hello world"`

lizhongyi_'s avatar
lizhongyi_ 已提交
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
- 在 swift(app-ios) 和 NSString 互转

在app-ios平台上,某些系统API或者三方库API可能使用NSString类型的字符串参数或者返回值。在需要时可以按照下面的方法进行转换:

```ts
// String 类型字符串转成 NSString 类型字符串
let str = "abcd"
// 方式一:
let str1 = NSString(string=str)
// 方式二:
let str2 = str as NSString

// NSString 类型字符串转成 String 类型字符串
let str3 = NSString(string="123")
// 方式一:
let str4 = String(str3)
// 方式二:
let str5 = str3 as string
```

D
DCloud_LXH 已提交
183 184 185 186 187 188 189 190 191
边界情况说明:

- 在不同平台上,字符串的长度限制不同,超出限制会导致相应的错误或异常
  * 编译至 JavaScript 平台时,最大长度取决于 JavaScript 引擎,例如在 V8 中,最大长度为 2^30 - 25,超出限制会报错:`Invalid string length`;在 JSCore 中,最大长度为 2^31 - 1,超出限制会报错:`Out of memory __ERROR`
  * 编译至 Kotlin 平台时,最大长度受系统内存的限制,超出限制会报错:`java.lang.OutOfMemoryError: char[] of length xxx would overflow`
  * 编译至 Swift 平台时,最大长度也受系统内存的限制,超出限制目前没有返回信息。

### 日期(Date)@date

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
192
日期对象表示日期,包括年月日时分秒等各种日期。[详见](buildin-object-api/date.md)
D
DCloud_LXH 已提交
193 194 195 196 197 198

### null

一个表明 null 值的特殊关键字。

有时需定义可为null的字符串,可以在类型描述中使用`|`操作符。
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
199

D
DCloud_LXH 已提交
200 201 202 203
```ts
let user: string | null
```

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
204 205 206 207 208 209
> 注意:uts 编译为kotlin和swift时不支持 undefined。每个有类型的变量都需要初始化或赋值。

### 数组(Array)

Array,即数组,支持在单个变量名下存储多个元素,并具有执行常见数组操作的成员。

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
210
js和swift的array,是可变长的泛型array。
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
211

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
212
而在kotlin中,其自带的array是不可变长的,length是固定的。只有arrayList是可变长的。
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
213

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
214
为了拉齐实现,UTS补充了新的Array,替代kotlin的array。它继承自kotlin的ArrayList,所以可以变长。
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
215

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
216
如果开发者需要使用原始的kotlin的不可变长的array,需使用 kotlin.array。
杜庆泉's avatar
杜庆泉 已提交
217

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
218 219 220
需要使用 kotlin.array 的场景和特有数字类型一样:
1. 某些系统API或三方原生SDK的入参或返回值强制指定了kotlin的array。
2. uts新增的可动态变长的array,在性能上不如固定length、不可变长的原始kotlin.array。但也只有在巨大量的运算中才能体现出毫秒级的差异。
杜庆泉's avatar
杜庆泉 已提交
221 222 223 224 225

#### 创建一个数组对象

`UTS`中数组的创建有两种方式:

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
226
1. 字面量创建
杜庆泉's avatar
杜庆泉 已提交
227

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
228
```ts
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
229 230
let a = [1,2,3];//支持
let a = [1,'2',3];//支持
杜庆泉's avatar
杜庆泉 已提交
231 232

// 需要注意的是,字面量创建的数组,不支持出现空的缺省元素
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
233
let a = [1,,2,3];//不支持
杜庆泉's avatar
杜庆泉 已提交
234 235
```

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
236 237
2. 创建数组对象
```ts
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
238 239 240 241
let a = new Array(1,2,3);//支持
let a = new Array(1,'2',3);//支持
let a = Array(1,2,3);//支持
let a = Array(1,'2','3');//支持
杜庆泉's avatar
杜庆泉 已提交
242 243 244 245 246 247
```

#### 遍历数组对象

在UTS语言中,推荐使用foreach来实现数组的遍历

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
248
```ts
杜庆泉's avatar
杜庆泉 已提交
249 250 251 252 253 254
const array1: string[] = ['a', 'b', 'c'];
array1.forEach((element:string, index:number) => {
    console.log(array1[index])
});
```

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
255
#### 更多API
杜庆泉's avatar
杜庆泉 已提交
256

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
257
更多Array的API,[详见](https://uniapp.dcloud.net.cn/uts/buildin-object-api/array.html)
杜庆泉's avatar
杜庆泉 已提交
258

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
259
#### kotlin平台的 Array 特性
杜庆泉's avatar
杜庆泉 已提交
260

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
261
<!-- 在kotlin平台上,Array 的具体实现类为: `io.dcloud.uts.UTSArray` -->
杜庆泉's avatar
杜庆泉 已提交
262

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
263
UTS 的 Array 拉齐了各个平台 Array 的功能和定义,可以满足大多数场景需要,但是在涉及与 系统API/三方sdk 交互部分,因为 系统API/三方sdk 是基于 java/kotlin 开发,因此调用时直接使用 UTS 的 Array 会产生类型不一致的错误。
杜庆泉's avatar
杜庆泉 已提交
264

杜庆泉's avatar
杜庆泉 已提交
265
举个例子:
杜庆泉's avatar
杜庆泉 已提交
266

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
267
```ts
杜庆泉's avatar
杜庆泉 已提交
268 269 270
let packageManager = UTSAndroid.getUniActivity()!.getPackageManager();
let intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
杜庆泉's avatar
杜庆泉 已提交
271
// 查询当前设备上安装了几个launcher
杜庆泉's avatar
杜庆泉 已提交
272 273 274
let resolveInfo = packageManager.queryIntentActivities(intent,0);
```

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
275
上面的代码向系统查询了有多少应用可以响应 `launcher`行为 ,返回的 resolveInfo 是一个 `List<ResolveInfo>`
杜庆泉's avatar
杜庆泉 已提交
276

杜庆泉's avatar
杜庆泉 已提交
277
这种情况下,我们可以将其先转换为UTS的Array对象再进行其他处理和操作
杜庆泉's avatar
杜庆泉 已提交
278

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
279
```ts
杜庆泉's avatar
杜庆泉 已提交
280
let launcherList = Array.fromNative(resolveInfo) 
杜庆泉's avatar
杜庆泉 已提交
281 282
console.log(clothing.length);
```
杜庆泉's avatar
杜庆泉 已提交
283 284 285

下面汇总了常用的转换场景和代码:

杜庆泉's avatar
杜庆泉 已提交
286
##### 1 我有一个Array 需要转换为其他类型
杜庆泉's avatar
杜庆泉 已提交
287

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
288
```ts
杜庆泉's avatar
杜庆泉 已提交
289
let utsArr= ["hello","world"]
杜庆泉's avatar
杜庆泉 已提交
290

杜庆泉's avatar
杜庆泉 已提交
291
// Array 转换 kotlin.collections.List
杜庆泉's avatar
杜庆泉 已提交
292 293
let kotlinList = utsArr.toKotlinList()

杜庆泉's avatar
杜庆泉 已提交
294
// Array 转换 kotlin.Array
杜庆泉's avatar
杜庆泉 已提交
295
let kotlinArray = utsArr.toTypedArray()
杜庆泉's avatar
杜庆泉 已提交
296 297 298

```

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
299
##### 2 我有一个原生类数组类型 需要转成成UTS的Array
杜庆泉's avatar
杜庆泉 已提交
300

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
301
```ts
杜庆泉's avatar
杜庆泉 已提交
302
// kotlin.collections.List 转换 Array
杜庆泉's avatar
杜庆泉 已提交
303
let utsArr= mutableListOf("hello","world")
杜庆泉's avatar
杜庆泉 已提交
304
let kotlinList = Array.fromNative(utsArr) 
杜庆泉's avatar
杜庆泉 已提交
305 306
```

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
307
```ts
杜庆泉's avatar
杜庆泉 已提交
308
// kotlin.Array 转换 Array
杜庆泉's avatar
杜庆泉 已提交
309
let utsArr= arrayOf("hello","world")
杜庆泉's avatar
杜庆泉 已提交
310
let kotlinList = Array.fromNative(utsArr)
杜庆泉's avatar
杜庆泉 已提交
311 312
```

杜庆泉's avatar
杜庆泉 已提交
313

D
DCloud_LXH 已提交
314 315
### any类型 @any

fxy060608's avatar
fxy060608 已提交
316
有时候,我们会想要为那些在编程阶段还不清楚类型的变量指定一个类型。 这些值可能来自于动态的内容,比如来自用户输入或第三方代码库。 这种情况下,我们不希望类型检查器对这些值进行检查而是直接让它们通过编译阶段的检查。 那么我们可以使用 any 类型来标记这些变量:
D
DCloud_LXH 已提交
317 318

```ts
fxy060608's avatar
fxy060608 已提交
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // okay, definitely a boolean
```

当你只知道一部分数据的类型时,any类型也是有用的。 比如,你有一个数组,它包含了不同的类型的数据:

```ts
let list: any[] = [1, true, "free"];
list[1] = 100;
```

### null类型 @null

uts 的类型系统可以消除来自代码空引用的危险。
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
334

fxy060608's avatar
fxy060608 已提交
335
许多编程语言中最常见的陷阱之一,就是访问空引用的成员会导致空引用异常。在 Java 中,这等同于 NullPointerException 或简称 NPE。
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
336

fxy060608's avatar
fxy060608 已提交
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
在 uts 中,类型系统能够区分一个引用可以容纳 null (可空引用)还是不能容纳(非空引用)。 例如,String 类型的常规变量不能容纳 null:

```ts
let a: string = "abc" // 默认情况下,常规初始化意味着非空
a = null // 编译错误
```

如果要允许为空,可以声明一个变量为可空字符串(写作 string | null):

```ts
let b: string | null = "abc" // 可以设置为空
b = null // ok
```

现在,如果你调用 a 的方法或者访问它的属性,它保证不会导致 NPE,这样你就可以放心地使用:

```ts
const l = a.length
```

但是如果你想访问 b 的同一个属性,那么这是不安全的,并且编译器会报告一个错误:

```ts
const l = b.length // 错误:变量“b”可能为空
```

但是,还是需要访问该属性,对吧?有几种方式可以做到。


#### 在条件中检测 null

首先,你可以显式检测 b 是否为 null:

```ts
if (b != null) {
  console.log(b.length)
}
```

编译器会跟踪所执行检测的信息,并允许你在 if 内部调用 length。

#### 安全的调用

访问可空变量的属性的第二种选择是使用安全调用操作符 ?.:

```ts
const a = "uts"
const b: string | null = null
console.log(b?.length)
console.log(a?.length) // 无需安全调用
```

如果 b 非空,就返回 b.length,否则返回 null,这个表达式的类型是 number | null。

安全调用在链式调用中很有用。例如,一个员工 Bob 可能会(或者不会)分配给一个部门。 可能有另外一个员工是该部门的负责人。获取 Bob 所在部门负责人(如果有的话)的名字, 写作:

```ts
bob?.department?.head?.name
```

如果任意一个属性(环节)为 null,这个链式调用就会返回 null。

#### 空值合并

空值合并运算符(??)是一个逻辑运算符,当左侧的操作数为 null 时,返回其右侧操作数,否则返回左侧操作数。

```ts
const foo = null ?? 'default string';
console.log(foo);
// Expected output: "default string"

const baz = 0 ?? 42;
console.log(baz);
// Expected output: 0
```

#### 非空断言

非空断言运算符(!)将任何值转换为非空类型。可以写 b! ,这会返回一个非空的 b 值(例如:在我们示例中的 String)或者如果 b 为 null,就会抛出一个异常。

```ts
const l = b!.length
D
DCloud_LXH 已提交
419
```