data-type.md 35.1 KB
Newer Older
W
wanganxp 已提交
1
## 类型@data-type
D
DCloud_LXH 已提交
2

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
3 4 5 6
强类型语言的特点,是数据类型要求严格。它带来2个好处:
1. 高性能:明确的类型有更大的优化空间,在iOS和Android等os上可以节省内存、提高运算速度;web端由于仍编译为js,不具有类型性能优化。
2. 安全的代码:强类型代码编写虽然没有弱类型自由,但类型检查、非空检查...各种检查可以提升代码的健壮性。

W
wanganxp 已提交
7 8
如果您是js开发者,那么需要一定的学习过程来掌握 UTS 的类型系统。总体原则是你将牺牲一些代码的灵活性,来换取代码的健壮性和高性能。

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
9
### 布尔值(boolean)
D
DCloud_LXH 已提交
10

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
11
布尔是简单的基础类型,只有2个值:`true``false`
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
12 13

```ts
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
14
let a:boolean = true // 定义类型并赋值字面量
W
wanganxp 已提交
15
let b = false // 未显式声明类型,但根据字面量可自动推导为布尔类型
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
16 17
let c:boolean // 定义类型但定义时未赋值
c = true // 后续为变量赋值字面量
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
18
```
D
DCloud_LXH 已提交
19

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
20 21 22 23
注意:
- 在js里,true == 1、 false == 0。但在其他强类型语言里,`1``0`是数字类型,无法和布尔类型相比较。
- 注意 boolean 不要简写成 bool

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
24
### 数字(number)
D
DCloud_LXH 已提交
25

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

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
28
UTS 在iOS和Android平台上新增了 number 类型,拉齐了web端的实现,方便开发者写全端兼容代码,也降低web开发者使用 uts 的门槛。
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
29

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

```ts
DCloud-yyl's avatar
DCloud-yyl 已提交
33 34 35 36
let a:number = 42       //a为number类型
let b:number = 3.14159  //b为number类型
let c = 42              //注意:目前版本推导c为Int类型,新版本将调整c为number类型
let d = 3.14159         //注意:目前版本推导d为float类型,新版本将调整d为number类型
D
DCloud_LXH 已提交
37 38
```

W
wanganxp 已提交
39 40
- 编译到kotlin平台时,number 利用 kotlin的 `Number`抽象类实现
- 编译到swift平台时,number 利用 `NSNumber` 实现
杜庆泉's avatar
杜庆泉 已提交
41

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
42
#### 平台专有数字类型
杜庆泉's avatar
杜庆泉 已提交
43

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
44
除了 number 类型,UTS 在 Android 和 iOS 设备上,也可以使用 kotlin 和 swift 的专有数字类型。
D
DCloud_LXH 已提交
45

W
wanganxp 已提交
46
日常开发使用 number 类型就可以。但是也有需要平台专有数字类型的场景:
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
47 48 49 50 51

1. 在 kotlin 和 swift 中,调用系统API或三方SDK的入参或返回值的类型,强制约定了平台专有数字类型。比如入参要求传入 Int,那么传入 number 会报错。比如方法返回了一个 Int,使用 number 类型的变量去接收,也会报错。
2. number 作为泛数字,性能还是弱于Int。在普通计算中无法体现出差异,但在千万次运算后,累计会产生毫秒级速度差异。

##### Kotlin 专有数字类型 @Kotlin
杜庆泉's avatar
杜庆泉 已提交
52 53 54

|类型名称|长度  |最小值       |最大值          |描述|
|:--     |:---  |:---         |:---           |:-- |
杜庆泉's avatar
杜庆泉 已提交
55 56 57 58 59 60 61 62
|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
杜庆泉 已提交
63
|Float   |32bit |1.4E-45F     |3.4028235E38                    |[浮点型](https://kotlinlang.org/docs/numbers.html#floating-point-types)|
W
wanganxp 已提交
64
|Double  |64bit |4.9E-324     |1.7976931348623157E308         |[浮点型](https://kotlinlang.org/docs/numbers.html#floating-point-types)|
杜庆泉's avatar
杜庆泉 已提交
65

W
wanganxp 已提交
66
基本数据类型会有jvm编译魔法加持,kotlin 会把 Int / Double 等非空类型编译为 基本数据类型,Int? / Double? 等可为空的类型编译为 Integer等包装类型,享受不到编译优化加持。
杜庆泉's avatar
杜庆泉 已提交
67

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
68
如果涉及大量运算,建议开发者不要使用 number、Int? ,要明确使用 Int等类型 [详情](https://kotlinlang.org/docs/numbers.html#numbers-representation-on-the-jvm)
杜庆泉's avatar
杜庆泉 已提交
69

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
70
##### Swift 专有的数字类型 @Swift
杜庆泉's avatar
杜庆泉 已提交
71

lizhongyi_'s avatar
lizhongyi_ 已提交
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
|类型名称    |长度   |最小值        				|最大值          					|描述|
|:--     	|:---  |:---         				|:---           					|:-- |
|Int8    	|8bit  |-128         				|127            					|整型|
|UInt8   	|8bit  |0            				|255            					|整型|
|Int16   	|16bit |-32768       				|32767          					|整型|
|UInt16  	|16bit |0            				|65535          					|整型|
|Int32      |32bit |-2147483648  				|2147483647     					|整型|
|UInt32     |32bit |0            				|4294967295     					|整型|
|Int64      |64bit |-9223372036854775808 		|9223372036854775807     			|整型|
|UInt64   	|64bit |0                    		|9223372036854775807 * 2 + 1     	|整型|
|Int  		|64bit |-9223372036854775808 		|9223372036854775807     			|整型(64位平台下)|
|UInt   	|64bit |0                 	 		|9223372036854775807 * 2 + 1     	|整型(64位平台下)|
|Int  		|32bit |-2147483648      	 		|2147483647     				  	|整型(32位平台下)|
|UInt   	|32bit |0            	  	 		|4294967295     				  	|整型(32位平台下)|
|Float   	|32bit |1.1754944E-38     	 		|3.4028235E38                    	|单精度浮点型|
|Float16   	|16bit |6.104e-05         	 		|65504.0                    		|半精度浮点型(仅iOS14.0及以上系统支持)|
|Float32   	|32bit |1.1754944E-38     	 		|3.4028235E38                    	|单精度浮点型,等同Float|
|Float64   	|64bit |2.2250738585072014E-308     |1.7976931348623157E308             |双精度浮点型,等同Double|
|Double  	|64bit |2.2250738585072014E-308     |1.7976931348623157E308         	|双精度浮点型|


- 注意:
	+ Swift 中 Int 类型是根据平台动态的,在 32 位设备下等同于 Int32, 在64位设备下等同于 Int64。因此建议整型使用 Int, 除非必要,且在保证不会溢出的场景下才使用 Int32、Int64。
	+ 同样,Swift 中的 UInt 类型也是根据平台动态的,在 32 位设备下等同于 UInt32, 在64位设备下等同于 UInt64。建议使用 UInt,非必要不使用 UInt32、UInt64。
	+ Float16 在 iOS14.0 及以上系统上才能使用,使用时注意做系统版本号判断。
	+ Float32 是 Float 的 typealise, 两者等价。
	+ Float64 是 Double 的 typealise, 两者等价。
杜庆泉's avatar
杜庆泉 已提交
99

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
100
##### 专有数字类型的定义方式
D
DCloud_LXH 已提交
101

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
102
使用下面的方法,虽然可能会被编辑器报语法错误(后续HBuilderX会修复这类误报),但编译到 kotlin 和 swift 运行是正常的。
杜庆泉's avatar
杜庆泉 已提交
103

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
104
- 声明特定的平台数字类型
W
wanganxp 已提交
105
 > 平台专有数字类型,均为首字母大写,注意与 number 首字母小写是不同的
杜庆泉's avatar
杜庆泉 已提交
106

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
107 108 109 110
```ts
let a:Int = 3 //注意 Int 是首字母大写
let b:Int = 4
let c:Double  = a * 1.0 / b
杜庆泉's avatar
杜庆泉 已提交
111 112
```

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

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
116 117
```ts
// #ifdef APP-IOS
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
118
let d:Int8 = 1 // Int8是swift平台专有类型
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
119 120
// #endif
```
杜庆泉's avatar
杜庆泉 已提交
121

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

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
124
#### 字面量类型自动推导@autotypefornumber
杜庆泉's avatar
杜庆泉 已提交
125

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
126
具体值,比如`42``"abc"`,称之为[字面量](literal.md)
杜庆泉's avatar
杜庆泉 已提交
127

W
wanganxp 已提交
128
字面量可以直接用于赋值、传参,比如 `let a = 42`,就是把`42`这个数字字面量赋值给了a。
杜庆泉's avatar
杜庆泉 已提交
129

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
130
不管是 ts 、kotlin 还是 swift,都具备字面量自动推导类型的能力,为 a 自动推导合适的类型。
杜庆泉's avatar
杜庆泉 已提交
131

W
wanganxp 已提交
132
**目前版本中,在未显式声明类型的情况下使用数字字面量赋值、传参,由平台语言自动推导为相应的类型**
杜庆泉's avatar
杜庆泉 已提交
133

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
134
但不同平台,推导结果不一样。
杜庆泉's avatar
杜庆泉 已提交
135

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
136 137 138
- ts 中,a 被推导为 number
- kotlin 中,a 被推导为 Int
- swift 中,a 被推导为 Int
杜庆泉's avatar
杜庆泉 已提交
139

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
140
上述只是一个简单的示例,再看一个复杂的例子,`let a = 1/10`
杜庆泉's avatar
杜庆泉 已提交
141

W
wanganxp 已提交
142
a 会被自动推导成什么类型?是Int、double、还是number?值是0还是0.1?在不同平台的差异更大。
D
DCloud_LXH 已提交
143

W
wanganxp 已提交
144
在web端,a 的类型是 number,值是0.1,但在 kotlin 中,类型是 Int,值是0.
D
DCloud_LXH 已提交
145

W
wanganxp 已提交
146
**为了统一各平台对字面量的自动推导规则,后续 uts 将接管和统一字面量类型推导。所有数字字面量、以及数字字面量组成的运算表达式,均默认推导为 number类型。**
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
147

W
wanganxp 已提交
148
未来,如您需要使用平台专有数字类型,需显式声明,如:
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
149
```ts
W
wanganxp 已提交
150
let c:Int = 42 //显式声明为Int
D
DCloud_LXH 已提交
151

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
152 153 154
function test(score: Int): boolean {
	return (score>=60) 
}
W
wanganxp 已提交
155
test(c)
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
156
```
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
157

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
158
当您调用系统或三方SDK的方法时,如果这些方法的入参要求Int,您之前直接通过字面量赋值`let a = 42`,就是 Int,但未来会变成 number,
W
wanganxp 已提交
159
导致类型不匹配报错。所以强烈建议您现在就更改代码写法,不依赖kotlin和swift的字面量自动推导,直接显式声明类型,改为`let a:Int = 42`
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
160

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
161
#### 各种数字类型之间的转换
D
DCloud_LXH 已提交
162

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
163
##### kotlin下转换数字类型
D
DCloud_LXH 已提交
164

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
165
所有的 number 都支持下列方法进行转换(部分类库API使用java编写,其要求的java类型与下列kotlin类型完全一致,可以直接使用
D
DCloud_LXH 已提交
166

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
167 168 169 170 171 172
- toByte(): Byte
- toShort(): Short
- toInt(): Int
- toLong(): Long
- toFloat(): Float
- toDouble(): Double
D
DCloud_LXH 已提交
173

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

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
176 177 178 179
- toUByte(): UByte
- toUShort(): UShort
- toUInt(): UInt
- toULong(): ULong
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
180

D
DCloud_LXH 已提交
181 182 183 184 185 186
```ts
let a:Int = 3
a.toFloat() // 转换为 Float 类型,后续也将支持 new Float(a) 方式转换
a.toDouble() // 转换为 Double 类型,后续也将支持 new Double(a) 方式转换
```

W
wanganxp 已提交
187
<!-- TODO:缺少如何把专有类型转为number @杜庆泉 -->
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
188 189

##### swift下转换数字类型
D
DCloud_LXH 已提交
190
```ts
lizhongyi_'s avatar
lizhongyi_ 已提交
191 192 193 194 195 196
// number转成特定类型
let num = 2
num.toInt() //将number 变量 num 转换为 Int 类型
num.toFloat() //将number 变量 num 转换为 float 类型
num.toInt64() // 将number 变量 num 转换为 Int64 类型

lizhongyi_'s avatar
lizhongyi_ 已提交
197 198 199 200
// 特定类型转成number
let f: Float = 5.0
let n = Number(f)

lizhongyi_'s avatar
lizhongyi_ 已提交
201
// 特定类型转成其他的特定类型
D
DCloud_LXH 已提交
202 203 204
let a:Int = 3
let b = new Double(a) // 将整型变量 a 转换为 Double 类型
```
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
205

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
206
#### number的边界说明
D
DCloud_LXH 已提交
207 208

- 在不同平台上,数值的范围限制不同,超出限制会导致相应的错误或异常
Y
yurj26 已提交
209 210 211
  * 编译至 JavaScript 平台时,数值范围为 ±1.7976931348623157e+308,超出范围会返回 `Infinity``-Infinity`
  * 编译至 Kotlin 平台时,整型的数值范围为 -9223372036854775808 到 9223372036854775807,超出范围会报错:`The value is out of range‌`。浮点型的数值范围为 ±1.7976931348623157e+308,超出范围会返回 `Infinity``-Infinity`。平台专有数字类型范围 [详见](#Kotlin)
  * 编译至 Swift 平台时,整型的数值范围为 -9223372036854775808 到 9223372036854775807,浮点型的数值范围为 ±1.7976931348623157e+308,超出范围会报错:`integer literal overflows when stored into 'NSNumber'`。平台专有数字类型范围 [详见](#Swift)
D
DCloud_LXH 已提交
212

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
213
#### 更多API
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
214
number内置对象有不少API,[详见](buildin-object-api/number.md)
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
215

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
216
### 字符串(string) @string
D
DCloud_LXH 已提交
217 218 219

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

W
wanganxp 已提交
220 221 222 223 224 225 226 227 228 229 230 231
string在多平台均可良好兼容。

```ts
let s1:string = "abc"  //显式声明string类型并赋值
let s2 = "abc" // 根据字符串字面量"abc",自动推导为string类型
let s3:string
s3 = "abc"
```

#### 平台专有字符串类型

- iOS 的 NSString
lizhongyi_'s avatar
lizhongyi_ 已提交
232

W
wanganxp 已提交
233
app-ios平台上原生有 NSString ,某些系统API或者三方库API可能使用NSString类型的字符串参数或者返回值。
lizhongyi_'s avatar
lizhongyi_ 已提交
234

W
wanganxp 已提交
235
定义NSString
lizhongyi_'s avatar
lizhongyi_ 已提交
236
```ts
W
wanganxp 已提交
237 238 239 240 241 242 243 244
let nstr = NSString(string="123") // 类型为NSString
```

可按照下面的方法在 string 和 NSString 之间转换:

- string 转 NSString
```ts
let str = "abcd" // 类型为string
lizhongyi_'s avatar
lizhongyi_ 已提交
245
// 方式一:
W
wanganxp 已提交
246
let nstr1 = NSString(string=str)  // 类型为NSString
lizhongyi_'s avatar
lizhongyi_ 已提交
247
// 方式二:
W
wanganxp 已提交
248 249
let nstr2 = str as NSString  // 类型为NSString
```
lizhongyi_'s avatar
lizhongyi_ 已提交
250

W
wanganxp 已提交
251 252 253
- NSString 转 string
```ts
let nstr3 = NSString(string="123") // 类型为NSString
lizhongyi_'s avatar
lizhongyi_ 已提交
254
// 方式一:
W
wanganxp 已提交
255
let str4 = String(nstr3)  // 类型为string
lizhongyi_'s avatar
lizhongyi_ 已提交
256
// 方式二:
W
wanganxp 已提交
257
let str5 = nstr3 as string  // 类型为string
lizhongyi_'s avatar
lizhongyi_ 已提交
258 259
```

D
DCloud_LXH 已提交
260 261 262 263 264 265 266 267 268
边界情况说明:

- 在不同平台上,字符串的长度限制不同,超出限制会导致相应的错误或异常
  * 编译至 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 已提交
269 270
日期对象表示日期,包括年月日时分秒等各种日期。

W
wanganxp 已提交
271 272
它的类型名称是首字母大写`:Date`。但通过new Date()赋值时,可以省略`:Date`

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
273
```ts
W
wanganxp 已提交
274 275
const myDate = new Date() // 通过new Date赋值时,可以省略:Date
const myDate1:Date = new Date() 
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
276
console.log(myDate instanceof Date) // Date用typeof会返回object,需使用instanceof判断
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
277 278 279 280
const year:number = myDate.getFullYear()
```

[详见](buildin-object-api/date.md)
D
DCloud_LXH 已提交
281

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
282 283 284 285 286

### 数组(Array)

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

W
wanganxp 已提交
287
`js``swift`的Array,是可变长的泛型Array。
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
288

W
wanganxp 已提交
289
而在`kotlin`中,其自带的Array是不可变长的,即数组的length是固定的。只有ArrayList是可变长的。
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
290

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

W
wanganxp 已提交
293
如果开发者需要使用原始的kotlin的不可变长的Array,需使用 `kotlin.Array`
杜庆泉's avatar
杜庆泉 已提交
294

W
wanganxp 已提交
295 296 297
需要使用平台专有数组类型的场景,也是如下2种情况:
1. 某些系统API或三方原生SDK的入参或返回值强制指定了kotlin的原生数组类型。
2. uts新增的可动态变长的Array,在性能上不如固定length、不可变长的原始kotlin.Array。但也只有在巨大量的运算中才能体现出毫秒级的差异。
杜庆泉's avatar
杜庆泉 已提交
298

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
299
#### 定义数组
杜庆泉's avatar
杜庆泉 已提交
300

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
301
`UTS` 中 Array 有多种创建方式,这些方式是等价的:
杜庆泉's avatar
杜庆泉 已提交
302

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

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
305
```ts
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
306 307
let a1 = [1,2,3];//支持
let a2 = [1,'2',3];//支持
杜庆泉's avatar
杜庆泉 已提交
308 309

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

W
wanganxp 已提交
313 314
2. 使用:Array<>定义数组项的类型

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
315
```ts
W
wanganxp 已提交
316
const a1:Array<string> = ["uni-app", "uniCloud", "HBuilder"] //表示数组内容都是string。如不能确定可以写Array<any>
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
317 318
```

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
319 320
3. 使用[]定义数组项的类型
```ts
W
wanganxp 已提交
321
const a1: string[] = ['a', 'b', 'c']; //表示数组内容都是string
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
322
```
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
323

W
wanganxp 已提交
324
4. 创建数组对象
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
325
```ts
W
wanganxp 已提交
326 327 328 329
let a1 = new Array(1,2,3);//支持
let a2 = new Array(1,'2',3);//支持
let a3 = Array(1,2,3);//支持
let a4 = Array(1,'2','3');//支持
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
330 331
```

W
wanganxp 已提交
332
字面量创建的数组,在uts的老版本上,kotlin自动推导数组类型,可能会推导成intArray,而不是uts的array。建议显式声明类型。
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
333 334

typeof 一个 array 得到的是 object。需使用 Array.isArray 或 instanceof 来判断数组类型。
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
335 336 337 338 339

```ts
let a1 = [1,2,3]
console.log(Array.isArray(a1)) // 返回true
console.log(a1 instanceof Array) // 返回true
杜庆泉's avatar
杜庆泉 已提交
340 341
```

lizhongyi_'s avatar
lizhongyi_ 已提交
342 343 344 345 346 347 348 349 350
- 注意:uts 不支持以 Array(arrayLength) 指定数组长度的方式创建一个数组。

```ts

// 下面的写法中,a1 将是一个当前 length 为1, 元素是 100 的整型数组。而不是 length 为 100 ,由 100 个空槽组成的数组。
const a1: Array(100); // [100], 当前数组长度为1

```

杜庆泉's avatar
杜庆泉 已提交
351 352
#### 遍历数组对象

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
353
使用foreach来实现数组的遍历
杜庆泉's avatar
杜庆泉 已提交
354

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
355
```ts
杜庆泉's avatar
杜庆泉 已提交
356 357
const array1: string[] = ['a', 'b', 'c'];
array1.forEach((element:string, index:number) => {
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
358 359
	console.log(element)
    console.log(array1[index]) //与上一行代码等价
杜庆泉's avatar
杜庆泉 已提交
360
});
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
361
// 打印结果是 a a b b c c
杜庆泉's avatar
杜庆泉 已提交
362 363
```

W
wanganxp 已提交
364
#### 平台专有数组类型
杜庆泉's avatar
杜庆泉 已提交
365

W
wanganxp 已提交
366
##### kotlin专有数组类型
杜庆泉's avatar
杜庆泉 已提交
367

W
wanganxp 已提交
368 369 370 371
- 专有数组类型清单
	* kotlin.collections.List
	* kotlin.Array
	* ...
杜庆泉's avatar
杜庆泉 已提交
372

W
wanganxp 已提交
373 374 375
- 专有数组类型定义方式

```ts
杜庆泉's avatar
杜庆泉 已提交
376 377 378 379
// kotlin.collections.List
let kotlinList= mutableListOf("hello","world")
// kotlin.Array
let kotlinArray = arrayOf("hello","world")
W
wanganxp 已提交
380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
```

- 专有数组类型 转 Array


```ts
// kotlin.collections.List 转换 Array
let kotlinList= mutableListOf("hello","world")
let utsArr = Array.fromNative(kotlinList) 
```

```ts
// kotlin.Array 转换 Array
let kotlinArray = arrayOf("hello","world")
let utsArr = Array.fromNative(kotlinArray)
```

举个例子。如下代码向系统查询了有多少应用可以响应 `launcher`行为 ,返回的 resolveInfo 是一个 `List<ResolveInfo>`
杜庆泉's avatar
杜庆泉 已提交
398

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
399
```ts
杜庆泉's avatar
杜庆泉 已提交
400 401 402
let packageManager = UTSAndroid.getUniActivity()!.getPackageManager();
let intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
杜庆泉's avatar
杜庆泉 已提交
403
// 查询当前设备上安装了几个launcher
杜庆泉's avatar
杜庆泉 已提交
404 405 406
let resolveInfo = packageManager.queryIntentActivities(intent,0);
```

W
wanganxp 已提交
407
可以将其先转换为UTS的Array对象再进行其他处理和操作
杜庆泉's avatar
杜庆泉 已提交
408

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
409
```ts
杜庆泉's avatar
杜庆泉 已提交
410
let launcherList = Array.fromNative(resolveInfo) 
杜庆泉's avatar
杜庆泉 已提交
411 412
console.log(clothing.length);
```
杜庆泉's avatar
杜庆泉 已提交
413

W
wanganxp 已提交
414
- Array 转 专有数组类型
杜庆泉's avatar
杜庆泉 已提交
415

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
416
```ts
W
wanganxp 已提交
417
let utsArr= ["hello","world"] //类型为Array
杜庆泉's avatar
杜庆泉 已提交
418

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

杜庆泉's avatar
杜庆泉 已提交
422
// Array 转换 kotlin.Array
杜庆泉's avatar
杜庆泉 已提交
423
let kotlinArray = utsArr.toTypedArray()
杜庆泉's avatar
杜庆泉 已提交
424 425 426

```

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

lizhongyi_'s avatar
lizhongyi_ 已提交
428
##### iOS 平台专有数组类型
杜庆泉's avatar
杜庆泉 已提交
429

lizhongyi_'s avatar
lizhongyi_ 已提交
430 431 432
	UTS 中的 Array 对应到 Swift 中就是 Array, 方法是通用的,无需转换。一般情况下,使用 Array 即可。
	但是,某些系统或者三方库 API 可能会要求 OC 的 NSArray、NSMutableArray 类型的数组,这个时候就需要进行转换。
	
W
wanganxp 已提交
433
- 专有数组类型清单
lizhongyi_'s avatar
lizhongyi_ 已提交
434 435
	* NSArray
	* NSMutableArray
W
wanganxp 已提交
436 437 438
	
- 专有数组类型定义方式

lizhongyi_'s avatar
lizhongyi_ 已提交
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483
1. 创建 NSArray
   NSArray 是 OC 中的不可变数组,顾名思义,数组创建完成之后就不可以再添加或者删除元素。因此,创建 NSArray 对象时就应该完成数组的初始化。
   可以通过以下方式创建 NSArray:
   
```ts
	// 方式一: 创建一个空数组,注意数组创建后就不可改变,不能再添加或者删除元素,应避免使用该方式。
	let a: NSArray = NSArray()  
	
	// 方式二: 用一个数组创建一个 NSArray, 推荐使用。同样,创建完成后数组不可变。
	let b: NSArray = NSArray(array=[1, 2, 3, 4]) // 等价于 any[],注意:不是等价于 number[]
	
	// 方式三: 用一个元素定义 NSArray, 不推荐使用
	let c: NSArray = NSArray(object=1)
	
	// 方式四:用不定长元素定义 NSArray, 可以使用
	let d: NSArray = NSArray(objects=1, "2", false, "ok")

```

2. 创建 NSMutableArray
   NSMutableArray 是 OC 中的可变数组,其是 NSArray 的子类,可变数组创建后可以增加或者删除元素。NSArray 的所有创建方式也都适用于 NSMutableArray
   
   ```ts
   	// 方式一: 创建一个空数组,其类型等价于 any[]
   	let a: NSMutableArray = NSMutableArray()  
	a.add(1) 	//添加一个元素
	a.add("22") //添加一个元素
	a.add(false) //添加一个元素
	a.remove(1) //移除一个元素
	a.removeObject(at=2) //移除一个指定下标的元素
	a.removeAllObjects() //移除全部元素
	a.removeLastObject() //移除最后一个元素
   	
   	// 方式二: 用一个数组创建一个 NSMutableArray, 推荐使用。
   	let b: NSMutableArray = NSMutableArray(array=[1, 2, 3, 4]) // 等价于 any[],注意:不是等价于 number[]
   	
   	// 方式三: 用一个元素定义 NSMutableArray
   	let c: NSMutableArray = NSMutableArray(object=1)
   	
   	// 方式四:用不定长元素定义 NSMutableArray
   	let d: NSMutableArray = NSMutableArray(objects=1, "2", false, "ok")
   
   ```
	
	
W
wanganxp 已提交
484 485
- 专有数组类型 转 Array

lizhongyi_'s avatar
lizhongyi_ 已提交
486 487 488 489 490 491 492 493 494 495 496 497
```ts

// 将 NSArray 转成 Array
let a: NSArray = NSArray(array=[1, 2, 3, 4]) // 等价于 any[],注意:不是等价于 number[]
let a1 = Array(a)

// 将 NSMutableArray 转成 Array
let b: NSMutableArray = NSMutableArray(array=[1, 2, 3, 4]) // 等价于 any[],注意:不是等价于 number[]
let b1 = Array(b)

```

W
wanganxp 已提交
498
- Array 转 专有数组类型
杜庆泉's avatar
杜庆泉 已提交
499

lizhongyi_'s avatar
lizhongyi_ 已提交
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521
```ts
// 定义一个 Array
let a = [1, 2, 3] //类型为number[]

// Array 转换成 NSArray
// 方式一:
let a1: NSArray = NSArray(array= a)

// 方式二:
let a2 = a as NSArray

// Array 转换成 NSMutableArray
let a3: NSMutableArray = NSMutableArray(array= a)

```

- 注意: 
	+ 无论是 NSArray 还是 NSMutableArray 对象创建后都等价于 any[] 类型的数组,此时 Swift 不再有类型推导,可以往可变数组中添加任意类型的非空元素。
	+ NSArray 和 NSMutableArray 类型的数组不接受空值 null, 任何情况下不要往这两种类型中注入 null。 否则,在运行时可能会引起应用闪退。
	+ Array 类型不能通过 as 方式转换成 NSMutableArray 类型。 但是可以通过 as 方式 转换成 NSArray 类型。
	+ Swift 中的 Array 是值类型,其和 TS 中 Array 的一点区别是 可以通 == 判断两个数组是否相等,只要两个数组的类型和元素一样,判等的结果就是 true。

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

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
523 524 525 526 527
#### 更多API

更多Array的API,[详见](https://uniapp.dcloud.net.cn/uts/buildin-object-api/array.html)


DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
528
### JSON@json
W
wanganxp 已提交
529

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
530
json 在 js 中用起来很自由,但在强类型语言中,不管kotlin、swift、dart...,都没有这么灵活。
W
wanganxp 已提交
531

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
532
json对象里的每个属性,都需要定义类型,才能安全读写。
W
wanganxp 已提交
533

Q
qiang 已提交
534
JSON 是 js 对象的一种表示方法,在 js 中可以直接用作对象表达式来初始化一个对象,而其他大多数语言都要求把json对象转为class、interface或type。
W
wanganxp 已提交
535 536 537

uts 当然也可以把 json 转 interface/type。有很多转换工具,不管是在线网页还是ide插件。

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
538
同时 uts 也提供了内置的 UTSJSONObject,它尽可能的为开发者提供接近js的灵活性。
W
wanganxp 已提交
539 540 541

#### 对象和数组

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
542
首先,我们需要区分JSON对象和由JSON对象组成的数组。
W
wanganxp 已提交
543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558

这是一个 UTSJSONObject 对象。jo 对象有2个属性,x和y,都是数字类型
```ts
let jo: UTSJSONObject = {
	"x": 1,
	"y": 2
}
```

这是一个 UTSJSONObject 数组。其数组项里有2个 UTSJSONObject 对象,每个对象都有x和y这2个属性。
```ts
let jr: UTSJSONObject[] = [
	{"x": 1,"y": 2},
	{"x": 2,"y": 1}
]
```
lizhongyi_'s avatar
lizhongyi_ 已提交
559

Q
qiang 已提交
560
在 js 中,可以定义一个变量,随意接受对象字面量或数组字面量。但在 UTS 里不行。如果数据内容是数组字面量,就不能定义为 UTSJSONObject。
lizhongyi_'s avatar
lizhongyi_ 已提交
561

W
wanganxp 已提交
562 563 564 565 566
也就是下面的代码是错误的,不能把数组赋值给对象。在接收网络传输的json数据时,非常需要注意这个类型匹配问题。类型不匹配会造成代码错误和应用崩溃。
```ts
let jo: UTSJSONObject = [{
	"x": 1,
	"y": 2
W
wanganxp 已提交
567
}] //错误,类型不匹配
Q
qiang 已提交
568 569 570 571 572 573 574 575 576 577 578 579
let jo: UTSJSONObject[] = [{
	"x": 1,
	"y": 2
}] //正确
let jo: Array<UTSJSONObject> = [{
	"x": 1,
	"y": 2
}] //正确
let jo = [{
	"x": 1,
	"y": 2
}] //正确,自动推断为 UTSJSONObject 数组
W
wanganxp 已提交
580
```
lizhongyi_'s avatar
lizhongyi_ 已提交
581 582 583

#### 定义 UTSJSONObject

W
wanganxp 已提交
584 585 586 587 588 589 590
可以通过 object 字面量的方式定义一个 UTSJSONObject 对象,编译器会根据字面量自动推导类型。

```ts
let jo = {
	x: 1,
	y: 2
}
W
wanganxp 已提交
591 592 593 594 595

let jo2 = {
	"a-b": 1, // 如果属性名包括-,则必须两侧加引号包围
	"y": 2
}
W
wanganxp 已提交
596 597
```

Q
qiang 已提交
598
严谨的JSON,x和y属性是需要两侧加引号包围的。对象字面量的属性名可以不加引号,当包含特殊字符时建议开发者加上引号。
W
wanganxp 已提交
599

Q
qiang 已提交
600
如果属性名包括`-`,则必须两侧加引号包围。尽管在 kotlin 中属性名称包含`$``_`等也需要转义,但是 UTS 中是无需特殊处理的,编译器会自动转换。
W
wanganxp 已提交
601

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
602
对于纯字面量,jo 后面的 `:UTSJSONObject` 可以省略,这些类型比较简单,可以自动推导类型。包括下面的多层嵌套,类型也不会推导出错。
lizhongyi_'s avatar
lizhongyi_ 已提交
603 604 605

```ts
let rect = {
W
wanganxp 已提交
606 607 608 609 610
	"x": 20,
	"y": 12,
	"size": {
		"width": 80,
		"height": 80
lizhongyi_'s avatar
lizhongyi_ 已提交
611 612 613 614
	}
}
console.log(rect)
```
W
wanganxp 已提交
615 616 617
<!-- 

对于复杂的json,通常会给它配套定义一个type,来描述这个json的内部数据类型。
lizhongyi_'s avatar
lizhongyi_ 已提交
618

W
wanganxp 已提交
619
此时需要使用`type`关键字,它的作用就是定义类型,在很多场景都可以使用。
lizhongyi_'s avatar
lizhongyi_ 已提交
620 621

```ts
W
wanganxp 已提交
622 623 624
type personType = {
	id : number,
	name : string
lizhongyi_'s avatar
lizhongyi_ 已提交
625
}
W
wanganxp 已提交
626 627 628 629 630 631 632
let a1=1,a2=2,b1="张三",b2="李四"
let personList [] : UTSJSONObject[]
personList = [
 	{ "id": a1, "name": b1 },
 	{ "id": a2, "name": b2 },
] as personType[]

lizhongyi_'s avatar
lizhongyi_ 已提交
633 634
```

W
wanganxp 已提交
635
很多json对象在构造时,是没有具体数据的。
lizhongyi_'s avatar
lizhongyi_ 已提交
636

W
wanganxp 已提交
637 638 639 640 641
```ts
let jo = {}
jo = JSON.parse({"result":true, "count":42})
```
 -->
lizhongyi_'s avatar
lizhongyi_ 已提交
642

W
wanganxp 已提交
643
有关字面量定义 UTSJSONObject 对象的信息,[详见](literal.md#object)
lizhongyi_'s avatar
lizhongyi_ 已提交
644

Q
qiang 已提交
645
除了字面量定义对象,经常用到的是通过 `JSON.parse()`,把一个 JSON 字符串转成对象。
W
wanganxp 已提交
646 647 648 649 650 651

```ts
let s = `{"result":true, "count":42}` // 常见场景中,这个字符串更多来自于网络或其他应用传输。
let jo = JSON.parse(s) // 这个代码适用于HBuilderX 3.9以前
```

Q
qiang 已提交
652
在 HBuilderX 3.9以前,`JSON.parse()`返回的`UTSJSONObject`。但因为有时网络或其他应用传入的是 JSON 根节点是数组,而不是对象,会导致崩溃。
W
wanganxp 已提交
653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673
所以从 HBuilderX 3.9起,`JSON.parse()`返回的类型改为`any`,即可能返回对象、也可能返回数组。这样就需要开发者自行再`as`一下来指定具体类型了。

新的写法是这样:
```ts
let s = `{"result":true, "count":42}` // 常见场景中,这个字符串更多来自于网络或其他应用传输。
let jo = JSON.parse(s) as UTSJSONObject

let sr = `[{"x":1, "y":2},{"x":3, "y":4}]` // 常见场景中,这个字符串更多来自于网络或其他应用传输。
let jr = JSON.parse(s) as UTSJSONObject[]
```

当然,还有更简短的写法,使用JSON的parseObject()和parseArray()方法:
```ts
let s = `{"result":true, "count":42}` // 常见场景中,这个字符串更多来自于网络或其他应用传输。
let jo = JSON.parseObject(s)

let sr = `[{"x":1, "y":2},{"x":3, "y":4}]` // 常见场景中,这个字符串更多来自于网络或其他应用传输。
let jr = JSON.parseArray(s)
```

全局对象JSON,除了parse()、parseObject()、parseArray()外,还有stringify()来把json转为字符串。[详见](buildin-object-api/json.md)
lizhongyi_'s avatar
lizhongyi_ 已提交
674

Q
qiang 已提交
675
#### 访问 UTSJSONObject 中的属性
lizhongyi_'s avatar
lizhongyi_ 已提交
676 677 678 679 680 681 682 683 684 685

```ts
let rect = {
	x: 20,
	y: 12,
	size: {
		width: 80,
		height: 80
	}
}
W
wanganxp 已提交
686 687
```

Q
qiang 已提交
688
以上述 rect 为例,访问 UTSJSONObject 中的数据,有如下3种方式:
W
wanganxp 已提交
689 690

1. `.`操作符
W
wanganxp 已提交
691 692
`rect.x``rect.size.width`
	
Q
qiang 已提交
693 694
	这种写法比较简单,和js习惯一致,但在 UTS 中限制较多。它的使用有如下前提:
	- 通过type声明了对象的数据结构,也就是需要单独定义一个type再使用。详见type章节。这也是大多数强类型使用对象字面量初始化的方式。
W
wanganxp 已提交
695
	- 如未定义type,则仅限于web和Android,在iOS上swift不支持`.`操作符。在Android上也只支持字面量定义json。如果是`JSON.parse()`转换的,则不能使用。
W
wanganxp 已提交
696 697 698 699
	
2. [""]下标属性
`rect["x"]`
	
Q
qiang 已提交
700
	这是一种通用的方式,不管通过字面量定义的 UTSJSONObject,还是通过 `JSON.parse()`,不管是 web、Android、iOS 哪个平台,都可以使用下标方式访问 UTSJSONObject 属性。
W
wanganxp 已提交
701

Q
qiang 已提交
702
	但下标返回嵌套的 UTSJSONObject 时,用起来比较麻烦,因为无法判断嵌套节点是对象还是数组,需要再 `as` 才能继续使用下一层数据。
W
wanganxp 已提交
703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719

```ts
let rect = {
	x: 20,
	y: 12,
	size: {
		width: 80,
		height: 80
	},
	border: [
		{color:"red",witdh:1},
		{color:"white",witdh:1},
		{color:"red",witdh:1},
		{color:"white",witdh:1}
	]
}

W
wanganxp 已提交
720
console.log(rect.x) //20 但iOS无法使用.操作符
W
wanganxp 已提交
721 722
console.log(rect["x"]) //20

W
wanganxp 已提交
723
console.log(rect.size.width) //80 但iOS无法使用.操作符
W
wanganxp 已提交
724 725
console.log((rect["size"] as UTSJSONObject)["width"]) //80

Q
qiang 已提交
726
// 如果存在嵌套,那么需要先把第一层转成 UTSJSONObject 或数组,之后再用下标访问下一层
lizhongyi_'s avatar
lizhongyi_ 已提交
727

W
wanganxp 已提交
728
console.log(rect.border[0].color); //报错,一旦使用了下标访问数组,后面就无法使用.操作符了
W
wanganxp 已提交
729
console.log(rect.border[0]["color"]); // red 但iOS无法使用.操作符
W
wanganxp 已提交
730
console.log((rect["border"] as UTSJSONObject[])[0]["color"]); // red
lizhongyi_'s avatar
lizhongyi_ 已提交
731 732 733

```

Q
qiang 已提交
734
如果是 `JSON.parse` 解析的数组,目前只能通过下标访问。
W
wanganxp 已提交
735 736 737 738 739 740 741 742

```ts
let listData = JSON.parse(`{"result":true, "count":42}`) as UTSJSONObject
let listArr = JSON.parse(`[{ id: 1, title: "第一组" },{ id: 2, title: "第二组" }]`) as UTSJSONObject[]
console.log(listData["count"]); //42
console.log(listArr[0]["title"]); //第一组
```

W
wanganxp 已提交
743
多层级下标访问时需要使用 as 转换为 UTSJSONObject  
DCloud-yyl's avatar
DCloud-yyl 已提交
744 745 746 747 748 749 750
```ts
var j = {"test":{
	"a-b": 1
}}
console.log((j['test'] as UTSJSONObject)['a-b']);
```

Q
qiang 已提交
751
3. 通过 keyPath 访问 UTSJSONObject 数据
杜庆泉's avatar
杜庆泉 已提交
752

Q
qiang 已提交
753
`HBuilderX` 3.9.0 之后的版本,UTSJSONObject 提供了另外一种属性访问方式,keypath。如果你了解 XPath、JSONPath 的话,这个概念类似。
杜庆泉's avatar
杜庆泉 已提交
754

Q
qiang 已提交
755
以下面的 UTSJSONObject 为例
杜庆泉's avatar
杜庆泉 已提交
756 757 758 759
```ts
let utsObj = {
	"username": "zhangsan",
	"age": 12,
杜庆泉's avatar
杜庆泉 已提交
760
	"isStudent":false,
杜庆泉's avatar
杜庆泉 已提交
761 762 763 764 765 766 767 768 769 770 771
	"address": {
		"countyCode": "86",
		"province": "beijing",
		"detailInfo": {
			"street": "the wall street",
			"buildingNo": "5"
		}
	}
}
```

杜庆泉's avatar
杜庆泉 已提交
772
我们可以通过 getString/getNumber/getBoolean/getJSON/getAny 等函数获得指定类型的属性,如果属性不存在,则返回null
杜庆泉's avatar
杜庆泉 已提交
773 774 775 776 777 778 779 780

```ts
// 打印结果:zhangsan
console.log(utsObj.getString("username"))
// 打印结果:12
console.log(utsObj.getNumber("age"))
// 打印结果:[object]
console.log(utsObj.getJSON("address"))
杜庆泉's avatar
杜庆泉 已提交
781 782 783 784 785 786
// 打印结果:false
console.log(utsObj.getBoolean("isStudent"))

// 打印结果:null
console.log(utsObj.getString("一个不存在属性"))

杜庆泉's avatar
杜庆泉 已提交
787 788 789 790 791 792 793 794
```

这种绑定类型的这对于原生开发者来说比较熟悉。但是需要特别注意的是: 如果属性名正确,但是属性类型不符合,那么不会返回对应的属性结果
```ts
// 打印结果:12
console.log(utsObj.getNumber("age"))
// 打印结果:null 
console.log(utsObj.getString("age"))
杜庆泉's avatar
杜庆泉 已提交
795 796 797

```

Q
qiang 已提交
798
在所有的getXXX函数中 `getAny` 是一个特殊的存在,它可以获取属性,而不要求限制类型,他的返回值是 any 类型。
W
wanganxp 已提交
799

W
wanganxp 已提交
800
需要注意的是 在强类型语言中使用 any 是一件危险的事情,如果你需要使用`getAny`请确保你已经充分了解了可能遇到的问题。
杜庆泉's avatar
杜庆泉 已提交
801 802 803 804 805 806

```ts
// 如果我们不确定属性类型,可以使用`getAny`来进行获取
console.log(utsObj.getAny("age") as Number)
// 如果我们不确定属性类型,可以使用`getAny`来进行获取
console.log(utsObj.getAny("address") as UTSJSONObject)
杜庆泉's avatar
杜庆泉 已提交
807 808
```

Q
qiang 已提交
809
在传统的属性访问中,UTSJSONObject 的嵌套是一种比较复杂的情况,需要我们层层解析才能获取数据:
杜庆泉's avatar
杜庆泉 已提交
810 811 812 813 814 815 816 817 818 819

```ts
// 获取 utsObj 中的 address属性
let addressObj = utsObj["address"] as UTSJSONObject
// 获取 address 中的 detail 属性
let detailInfoObj = utsObj["detailInfo"] as UTSJSONObject
// 结果:the wall street
let street = utsObj["street"] as String
```

W
wanganxp 已提交
820
上面的写法,啰嗦且容易出错。因此,我们提供了更易用的 keypath 写法,帮助开发者摆脱复杂的对象嵌套关系:
杜庆泉's avatar
杜庆泉 已提交
821 822 823 824 825 826
```ts
// 结果:the wall street
let street = utsObj.getString("address.detailInfo.street")
```


lizhongyi_'s avatar
lizhongyi_ 已提交
827

D
DCloud_LXH 已提交
828 829
### any类型 @any

W
wanganxp 已提交
830 831
有时会遇到在编程阶段还不清楚类型的变量。这些值可能来自于动态的内容,比如来自用户输入或第三方代码库。
这种情况下,我们不希望类型检查器对这些值进行检查而是直接让它们通过编译阶段的检查。那么我们可以使用 `any` 类型来标记这些变量:
D
DCloud_LXH 已提交
832 833

```ts
fxy060608's avatar
fxy060608 已提交
834 835 836 837 838 839 840 841 842 843 844 845
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;
```

lizhongyi_'s avatar
lizhongyi_ 已提交
846 847 848
- 注意:在 TS 中可以将 null 赋值给 any 类型的变量,但是在 Swift 和 Kottlin 中,any 类型属于非空类型,也就是不能将 null 赋值给 any 类型的变量。因此 在 UTS 中 也不能将 null 赋值给 any 类型,以免编译失败。

	
fxy060608's avatar
fxy060608 已提交
849 850
### null类型 @null

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
851 852
一个表明 null 值的特殊关键字。

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

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

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
857
在 uts 中,类型系统能够区分一个引用可以容纳 null (可空引用)还是不能容纳(非空引用)。 例如,string 类型的常规变量不能容纳 null:
fxy060608's avatar
fxy060608 已提交
858 859 860 861 862 863

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

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
864
如果要允许为空,可以声明一个变量为可空字符串(写作 string | null)
fxy060608's avatar
fxy060608 已提交
865 866 867 868 869 870

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

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
871 872
但这不代表 uts 支持广泛的联合类型。实际上目前仅有可为空才能这么写。

fxy060608's avatar
fxy060608 已提交
873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901
现在,如果你调用 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。

#### 安全的调用

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
902
访问可空变量的属性的第二种选择是使用安全调用操作符 `?.`
fxy060608's avatar
fxy060608 已提交
903 904 905 906

```ts
const a = "uts"
const b: string | null = null
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
907 908
console.log(a.length) // a是明确的string类型,它的属性可以直接调用,无需安全调用
console.log(b?.length) // b可能为null,null没有length属性,在没有判空时,.操作符前面必须加?标记
fxy060608's avatar
fxy060608 已提交
909 910
```

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
911
如果 b 非空,就返回 b.length,否则返回 null,`b?.length`这个表达式的类型是 number | null。
fxy060608's avatar
fxy060608 已提交
912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936

安全调用在链式调用中很有用。例如,一个员工 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
```

#### 非空断言

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
937
非空断言运算符(!)将任何值转换为非空类型。可以写 b! ,这会返回一个非空的 b 值(例如:在我们示例中的 string)或者如果 b 为 null,就会抛出一个异常。
fxy060608's avatar
fxy060608 已提交
938 939 940

```ts
const l = b!.length
D
DCloud_LXH 已提交
941
```
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
942

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
943
### 其他
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
944

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
945
- 关于undefined
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
946

DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
947
js中的 undefined类型表示变量被定义,但是未赋值或初始化。
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
948 949 950 951

uts 编译为kotlin和swift时不支持 undefined。即不允许变量未赋值。

每个有类型的变量都需要初始化或赋值。
DCloud_Heavensoft's avatar
DCloud_Heavensoft 已提交
952 953