ArkTs学习之Map 对象, Map与字典的区别, Map 与 Record的区别
一、Map 对象
1. Map的基础操作
🔊:初始化Map的键和值,它们可以是任何类型, 注意Map中所有的键或所有的值必须是相同类型
TypeScript 使用 Map 类型 和 new 关键字来创建 Map:
let myMap = new Map();
但是,在ArkTs中我们需要明确具体的类型,不然会报错
let myMap = new Map(); //🙅错误:Use explicit types instead of "any", "unknown" (arkts-no-any-unknown) <ArkTSCheck> let myMap1 = new Map<string,string>() //🙆正确:明确了具体Map中键值对的类型,为[string,string]
初始化 Map,也可以以数组的格式来传入键值对:
let myMap = new Map([ ["key1", "value1"], ["key2", "value2"] ]);
🔊:通过map.set设置键值对,返回该Map对象
myMap.set("key3", 'value3') console.log(myMap)
🔊:通过map.get获取键对应的值,如果不存在,则返回undefined
let getmap = myMap.get("key1") let getmap2 = myMap.get("key999") console.log(getmap); //'value1' console.log(getmap2); //undefine
🔊:通过map.delete()删除键值对,删除则返回true,未删除则返回false
let deletemap = myMap.delete("key2") let deletemap1 = myMap.delete("key999") console.log(`${deletemap}`) // true console.log(`${deletemap1}`); // false
🔊:通过map.has()判断 Map中是否包含所查找的键值,返回布尔型
let hasmap = myMap.has("key1") let hasmap2 = myMap.has("key2") console.log(`${hasmap}`) //true console.log(`${hasmap2}`) //true
🔊:通过map.clear()移除所有键值对,清除Map。无法返回值
let clearmap = myMap.clear() console.log(`${clearmap}`) //undefine console.log(`${myMap}`) // 空 [object Map] 对象
🔊:通过map.size 获取对象键/值对的数量。返回number型
let sizemap = myMap.size console.log(`${sizemap}`) //2
🔊:map.keys() - 返回一个 Iterator 对象, 包含了 Map 对象中每个元素的键 。
let keysmap = myMap.keys() console.log(`${keysmap}`) // 所有的keys:[object Map Iterator]
🔊:map.values() – 返回一个新的Iterator对象,包含了Map对象中每个元素的值 。
let valuesmap = myMap.values() console.log(`${valuesmap}`) // 所有的values:[object Map Iterator]
2. Map的迭代
Map的迭代有多种方式
🔊 1. 使用for...of进行迭代,返回一个包含键值对的数组
let myMap = new Map<number,string>([ [0,'zero'], [1,'zero'] ]) //🙅错误:arkTs不支持 Destructuring variable declarations are not supported (arkts-no-destruct-decls) <ArkTSCheck> for (let [key,value] of myMap) { console.log(`key:${key}--value:${value}`) } //🙆正确:可以获取myMap中的具体的元组map,然后再根据索引获取 for (let map of myMap){ console.log(`key:${map[0]}--value:${map}[1]`) }
🔊 2. 使用forEach进行迭代,它会接受一个回调函数作为参数
let myMap = new Map<number,string>([ [0,'zero'], [1,'zero'] ]) //通过foreach 迭代 myMap.forEach((key,value)=>{ console.log(`key:${key}--value:${value}`) })
🔊 3. 使用 keys 方法迭代所有的键
let myMap = new Map<number,string>([ [0,'zero'], [1,'zero'] ]) //通过keys 迭代出所有key for (let key of myMap.keys()) { console.log(`${key}`) }
🔊 4. 使用 values 方法迭代所有的值
let myMap = new Map<number,string>([ [0,'zero'], [1,'zero'] ]) //通过values 迭代出所有value for (let value of myMap.values()) { console.log(`${value}`) }
⚠️:需要注意的是,使用 for...of 或 forEach 迭代时,键值对的顺序与添加顺序一致;而使用 keys 或 values 迭代时,顺序与添加顺序无关。
二、Map 与 字典 的区别
对于上面两个数据,有以下区别
🔊 1. 数据类型:
statusColorMap1 是一个普通的JavaScript对象。
statusColorMap2 是一个Map对象。
🔊 2. 键的类型:
statusColorMap1 的键是数值(number)类型。
statusColorMap2 的键是字符串(string)类型,即使你在初始化时写的是数字,但在Map中它们会被自动转换为字符串。
🔊 3. 键的排序:
普通对象的键是无序的,这意味着你不能期望遍历对象的属性时总是以特定的顺序获得它们(尽管在大多数现代浏览器中,当你以特定的顺序插入属性时,它们会按该顺序返回,但这并不是规范所保证的)。
Map对象的键是按照插入顺序排序的。
🔊 4. 键和值的获取:
使用statusColorMap1[key]来获取或设置对象的值。
使用statusColorMap2.get(key)来获取Map的值,使用statusColorMap2.set(key, value)来设置值。
🔊 5. 键的存在性检查:
对于对象,你可能需要使用key in object来检查键是否存在。
对于Map,你可以使用map.has(key)来检查键是否存在。
🔊 6. 迭代:
你可以使用for...in循环(但要小心原型链上的属性)或Object.keys(), Object.values(), Object.entries()等方法来迭代对象的键和值。
对于Map,你可以使用for...of循环直接迭代其键-值对,或者使用map.keys(), map.values(), map.entries()等方法来获取迭代器。
🔊 7. 大小:
对于对象,你需要使用Object.keys(object).length来获取其大小(即属性的数量)。
对于Map,你可以使用map.size属性来获取其大小。
🔊 8. 其他方法和特性:
Map对象提供了许多其他方法和特性,如clear()(清除所有键-值对)、delete(key)(删除指定键的键-值对)等,这些在普通对象中是没有的(除非你自己实现这些方法)。
总的来说,选择使用对象还是Map取决于你的具体需求。如果你需要有序的键、更方便的迭代或更多的方法,那么Map可能是一个更好的选择。但是,如果你只是需要简单的键值对存储,并且不关心键的排序或迭代顺序,那么对象可能就足够了。
三、Map
与 Record的区别
1. Map 与 Record 两者的区别
🔊 Record<string, string>
定义: Record 是 TypeScript 的一种类型,用于表示一个对象,其中所有的键是特定类型(通常是 string 或 number),所有的值也是特定类型。
语法:
const record: Record<string, string> = { "key1": "value1", "key2": "value2" };
特性:
Record 用于描述对象的结构和类型。
对象的键是字符串(或其他类型如数字),值的类型是固定的。
适合描述静态且结构固定的键值对集合。
不提供内建的方法来操作数据,如 .set(), .get() 等。
🔊 Map<string, string>
定义: Map 是 JavaScript 内建的数据结构,用于存储键值对,其中键和值都可以是任意类型(在这里是 string 类型)。
语法:
const map = new Map<string, string>([ ["key1", "value1"], ["key2", "value2"] ]);
特性:
Map 是一个类,提供了丰富的方法来操作键值对,比如 .set(), .get(), .delete(), .has(), .clear()。
保持键值对的插入顺序,并可以通过迭代来访问。
键和值的类型可以是任何类型,但在这个例子中是 string。
Map 提供了更灵活的数据操作能力和性能优化(如基于哈希的查找效率)。
🔊 总结
Record: 用于描述对象的固定结构和类型。适合静态数据和简单的键值对存储。
Map: 更加灵活的数据结构,适用于动态操作和需要保持插入顺序的键值对集合。提供了内建的操作方法。
2. Map
与Record
类型转换函数
在HarmonyOS中,Record
类型提供了一种方便的方式来定义具有特定键值对结构的对象。然而,Record
本身没有直接修改其元素的内置方法,但是我们可以借助 Map
类型来实现对 Record
数据的增删改操作,然后再转换回 Record
类型。
🔊 Map
转为Record
在 TypeScript 中,我们定义了 mapToRecord
函数来实现从 Map
到 Record
的转换。
// Map转为Record export function mapToRecord(myMap: Map<string, string>): Record<string, string> { return Object.fromEntries(myMap.entries()) as Record<string, string>; }
这个函数利用了 Object.fromEntries
方法,它接受一个可迭代对象(这里是 Map
的 entries
方法返回的迭代器),并将其转换为一个普通对象。然后通过类型断言将其转换为 Record<string, string>
类型。
🔊 Record
转为Map
相应地,recordToMap
函数用于将 Record
转换为 Map
。
// Record转为Map export function recordToMap(myRecord: Record<string, string>): Map<string, string> { let myMap: Map<string, string> = new Map(); for (const key in myRecord) { myMap.set(key, myRecord[key]); } return myMap; }
该函数遍历 Record
对象的键,将每个键值对添加到新创建的 Map
中,最后返回这个 Map
。
3. 在 ArkTS 中操作 Record
数据
在 ArkTS 项目中,首先导入上述定义的转换函数。
import { mapToRecord, recordToMap } from './utils';
接着定义一个初始的 Record
对象 res
。
let res: Record<string, string> = { 'item1': '1', 'item2': '2' };
然后将其转换为 Map
类型,以便进行增删操作。
let myMap: Map<string, string> = recordToMap(res); myMap.set('item3', '3'); // 添加元素 myMap.delete('item1'); // 删除元素
在添加元素时,使用 Map
的 set
方法添加一个新的键值对 'item3': '3'
;删除元素则通过 delete
方法删除键为 'item1'
的键值对。
最后,再将修改后的 Map
转换回 Record
类型。
let myRecord = mapToRecord(myMap);
在 Index
组件的 build
函数中,当点击按钮时,将修改后的 Record
对象以 JSON 字符串的形式输出到控制台。
@Entry @Component struct Index { build() { Row() { Column() { Button('change Record') .onClick(() => { console.log('myRecord:', JSON.stringify(myRecord)); // myRecord: {"item2":"2","item3":"3"} }) } .width('100%') } .height('100%') } }