无论在C#,还是在JS/TS/UTS中,万物皆对象。创建对象的方式有两种,一是通过类的实例化,二是直接通过字面量。JS/TS/UTS中,创建字面量对象非常普遍,JS中可以随意创建,且对象的属性和方法可以随意增减覆盖;但TS/UTS是强类型,必需为字面量对象定义类型,且对象的属性方法不能随意增减覆盖,TS/UTS中,定义字面量对象的类型,有两种方式,一是interface,二是type。建议使用type,本节以type为例,关于interface的使用,详见《接口》。而C#中,也通过匿名对象的方式来创建
一、TS/UTS中的字面量对象
1.1 使用类型注解方式创建和使用字面量对象
//注意,类型注解中,成员使用分号分隔。这种方式比较少用。
let person:{ name:string; age:number; sayHi():void } = {
name:"jack",
age:28,
sayHi(){...}
};
//方法参数中使用
function myAxios(config:{url:string; method?:string}){}
//对象成员的读取和修改
let name = person.name; //读取
person.age = 18; //修改
person.sayHi(); //方法成员的调用
1.2 使用type方式创建字面量对象
//1、基本使用========================================================================
type Person = {
name:string,
age: number,
sayHi():void,
sayHiAgain:()=>void //箭头函数方式
};
let person:Person = { //冒号方式
name:"jack",
age:28,
sayHi(){...},
sayHiAgain(){...}
};
let person = {
name:"jack",
age:28,
sayHi(){...},
sayHiAgain(){...}
} as Person //as方式
//2、数组对象========================================================================
let personList:Person[] = [
{ id: 1, name: "zhangsan", age: 18 },
{ id: 2, name: "lisi", age: 16 },
]
let personList = [
{ id: 1, name: "zhangsan", age: 18 },
{ id: 2, name: "lisi", age: 16 },
] as Person[]
//3、嵌套复杂对象====================================================================
//注意顺序,如果在同一个文件中定义,Address要先定义,否则Person找不到Address
//也可以分成两个文件,在定义Person的文件中,通过import引入Address
type Address = {
city:string,
street:string,
doorNum?:string //使用?运算符,表示可空
};
type Person = {
name:string,
age:number,
phone:string|null, //使用联合类型,表示可空
address:Address
};
let person = {
name:"mc",
age:28,
address:{
city:"sd",
street:"rg",
doorNum:"1001"
}
}
//4、模块中使用type==================================================================
export type Person = {...}; //导出
import type {Address,Person} from "..."; //导入
//5、TS和UTS中使用type的区别=========================================================
//TS中的type不仅可以为对象指定类型,实际可以为任意类型指定别名-------
type MyString = string; //MyString成为字符串类型的别名
type NumStr = number | string; //NumStr可以是数值或字符串类型,称为联合类型
type Phone = string | null; //Phone是可空的字符串
type MyOnlyStr = "sex"; //字面量类型,MyOnlyStr类型只有一个值sex
type MyStr = "male" | "female" | "unknown"; //可选字面量,MyStr可以是三个字符串中的一个
//***UTS对type联合类型只有两种:
//一种是字面量联合类型(运行时确定):
type a = 1|2|3;
//一种是可空联合类型:
type b = string | null
//uts中引入类型,推荐import {Address} from...,而非import type {Address} from...
//无论是type、JSON或UTSJSONObject,key不要用_、+、-等敏感符号,处理起来很麻烦,TS也适用
1.3 JSON字符串转化为字面量对象
//TS和UTS中通用方式==================================================================
type Person = {
id: number,
name: string
};
let jsonString:string = `{
"id": 1,
"name": "zhangsan"
}`;
//类型注解方式
let person:Person = JSON.parse(jsonString);
//泛型方式
let person = JSON.parse<Person>(jsonString);
//对象数组使用Person[]
//UTS中建议使用=====================================================================
JSON.parseObject<T>(text: string) //对象
JSON.parseArray<T>(text: string) //对象数组
1.4 UTS中使用UTSJSONObject(仅UTS)
UTS中提供了UTSJSONObject类型,这是字面量对象的通用类型,可以在不定义字面量对象具体类型的前提下,直接使用。但是,仍然建议使用type。
//1、定义UTSJSONObject类型===========================================================
//自动推导为UTSJSONObject类型,可以通过let classA:UTSJSONObject显式申明
let classA = {name:"zs", age:28}
//自动推导为UTSJSONObject[]类型,可以通过let classB:UTSJSONObject[]显式申明
let classB = [
{name:'语文',id:1},
{name:'数学',id:2}
]
//2、UTSJSONObject的读取=============================================================
//方式一:使用下标方式,操作比较麻烦----------------------------------
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}
]
}
rect["x"])//20 但类型其实未知,如果继续操作则需要as
(rect["size"] as UTSJSONObject)["width"]//80 使用as后需要整体用()括起来再继续使用下标[]
(rect["border"] as UTSJSONObject[])[0]["color"]//red 多层嵌套
//方式二:使用UTSJSONObject的实例方法------------------------------------
let utsObj = {
"username": "zhangsan",
"age": 12,
"isStudent":false,
"address": {
"countyCode": "86",
"province": "beijing",
"detailInfo": {
"street": "the wall street",
"buildingNo": "5"
}
}
}
utsObj.getString("username") // 结果:zhangsan
utsObj.getNumber("age") // 结果:12
utsObj.getJSON("address") // 结果:[object]
utsObj.getBoolean("isStudent") // 结果:false
utsObj.getString("address.detailInfo.street") // 结果:the wall street,深层次读取
utsObj.getString("一个不存在属性") // 结果:null
//如果我们不确定属性类型,可以使用`getAny`来进行获取
//但操作any类型比较危险,还是建议显式转换后再使用
utsObj.getAny("age") as Number
//其余方法:
getArray(key):Array|null
get(key):any|null
set(key:string,value:any)
//方式三:将UTSJSONObject类型转换为map类型后再进行操作---------------------------
//注意toMap()只能转对象类型,不能转对象数组
let userA = {
name: "zhangsan",
age: 12,
sex: 0
} // userA 被推导为UTSJSONObject
let userMap = userA.toMap() //UTSJSONObject有toMap方法
//map的实例属性:
userMap.size
//map的实例方法:
userMap.get(key), userMap.set(key), userMap.has(key), userMap.delete(key)
userMap.clear(), userMap.forEach((value,key)=>{},thisArg?)
//2、UTSJSONObject的修改============================================================
/*
1、通过下标方式读取到的值,可以直接修改
2、可以调用实例方法set(key:string,value:any)修改
3、使用type类型as后,就是一个自定义类型的实例了,可以像操作普通对象一样直接修改
4、toMap()后,就是一个map类型的实例了,使用map的实例方法进行操作
5、通过get***()实例方法,直接读取值,不能进行修改
*/
//2、将JSON字符串转为UTSJSONObject类型===============================================
//转换对象类型
let jsonData1 = `{"result":true, "count":42}`
let utsjsonData1 = JSON.parseObject(jsonData)
//转换对象数组类型
let jsonData2 = `[{"x":1, "y":2},{"x":3, "y":4}]`
let utsjsonData2 = JSON.parseArray(jsonData)
//也可以使用JSON.parse(),但要显式进行类型转换,不推荐
//JSON.parse(jsonData) as UTSJSONObject
//parseObject和parseArray的泛型版本,可以直接转换为相应类型,更加方便
JSON.parseObject<T>(text: string) //对象
JSON.parseArray<T>(text: string) //对象数组
1.5 索引签名和映射类型
TS的对象类型中,还有一个模块是索引签名和映射类型,但在UTS和ArkTS中,这两个模块好像都禁用了,因为太接近动态语言了。所以就不深入了,仅举两个简单的例子。
//1、索引签名,无法确定有哪些有多少属性时==============================================
//约束键和值的类型
type AnyObject = {
[key:string]:number
}
//只有键和值的类型匹配就可以,键名以及成员数量不受限制
let obj:AnyObject = {
a:1,
b:2,
c:3
}
//2、映射类型,基于旧类型创建新类型,减少重复创建=======================================
type PropKeys = "x"|"y"|"z";
type Type1 = {x:number; y:number; z:number} //正常创建方式
type Type2 = {[Key in Prokeys]:number} //映射方式,骚操作
type Props = {a:number; b:number; c:number}
type Types = {[Key in keyof Props]:number}
二、C#中的字面量对象-匿名对象
//基本使用===========================================================================
var obj = new { Name = "Alice", Age = 25 };
Console.WriteLine(obj.Name);
Console.WriteLine(obj.Age);
//Linq的select中使用=================================================================
List<Person> people = new List<Person>
{
new Person { Name = "Alice", Age = 25 },
new Person { Name = "Bob", Age = 30 }
};
var result = people.Select(p => new
{
Name = p.Name,
AgeGroup = p.Age > 25? "Old" : "Young"
});
/*匿名对象的使用限制
1)没有方法和行为
2)所有属性都是只读的
3)只能作为局部变量使用,不能在类成员中使用
4)它是由编译器在编译时生成,所以不能作为方法参数、也不能作为数据持久化的模型
*/