Map 和 Set (映射和集合)
Map 是一个带键的数据项的集合,就像一个对象一样。但是它们直接最大的差别是 Map 允许任何类型的键。
方法和属性如下:
new Map()
—— 创建 map。map.set(key, value)
—— 根据键存储值。map.get(key)
—— 根据键来返回值,如果map
中不存在对应的key
,则返回undefined
。map.has(key)
—— 如果key
存在则返回true
,否则返回false
。map.delete(key)
—— 删除指定键的值。map.clear()
—— 清空 map。map.size
—— 返回当前元素个数。
let map = new Map();
map.set('1', 'str1');
// 字符串键
map.set(1, 'num1');
// 数字键
map.set(true, 'bool1');
// 布尔值键// 还记得普通的 Object 吗? 它会将键转化为字符串
// Map 则会保留键的类型,所以下面这两个结果不同:
alert( map.get(1));
// 'num1'
alert( map.get('1') );
// 'str1'alert( map.size );
// 3
Map 可以使用对象作为键。
let john = { name: "John" };
// 存储每个用户的来访次数
let visitsCountMap = new Map();
// john 是 Map 中的键
visitsCountMap.set(john, 123);
alert( visitsCountMap.get(john) );
// 123
使用对象作为键是
Map
最值得注意和重要的功能之一。对于字符串键,Object
(普通对象)也能正常使用,但对于对象键则不行。尝试一下
let john = { name: "John" };
let visitsCountObj = {};
// 尝试使用对象visitsCountObj[john] = 123;
// 尝试将 john 对象作为键// 是写成了这样!
alert( visitsCountObj["[object Object]"] );
// 123
注意:链式调用。每一次 map.set 调用都会返回 map 本身,所以我们可以进行链式调用
map.set('1', 'str1')
.set(1, 'num1')
.set(true, 'bool1');
Map 迭代
map.keys()
—— 遍历并返回所有的键(returns an iterable for keys),map.values()
—— 遍历并返回所有的值(returns an iterable for values),map.entries()
—— 遍历并返回所有的实体(returns an iterable for entries)[key, value]
,for..of
在默认情况下使用的就是这个。
let recipeMap = new Map([
['cucumber', 500],
['tomatoes', 350],
['onion',50]
]);
// 遍历所有的键(vegetables)
for (let vegetable of recipeMap.keys()) {
alert(vegetable);
// cucumber, tomatoes, onion
}// 遍历所有的值(amounts)
for (let amount of recipeMap.values()) {
alert(amount);
// 500, 350, 50
}// 遍历所有的实体 [key, value]
for (let entry of recipeMap) { // 与 recipeMap.entries() 相同
alert(entry);
// cucumber,500 (and so on)
}
使用插入顺序
迭代的顺序与插入值的顺序相同。与普通的
Object
不同,Map
保留了此顺序。而且 Map 有内置的 forEach 方法,和 Array 类似
// 对每个键值对 (key, value) 运行 forEach 函数
recipeMap.forEach( (value, key, map) => {
alert(`${key}: ${value}`);
// cucumber: 500 etc
});
Object.entries: 从对象创建Map 当创建一个 Map 后,我们可以传入一个带有键值对的数组来继续初始化。
// 键值对 [key, value] 数组
let map = new Map([
['1','str1'],
[1,'num1'],
[true, 'bool1']
]);
alert( map.get('1') );
// str1
【6-JS-数据类型-Map 和 Set (映射和集合)】也可以
let obj = {
name: "John",
age: 30
};
let map = new Map(Object.entries(obj));
alert( map.get('name') );
// John
这里,
Object.entries
返回键/值对数组:[ ["name","John"], ["age", 30] ]
。这就是 Map
所需要的格式。Object.fromEntries:从 Map 创建对象
Object.fromEntries
方法的作用是相反的:给定一个具有 [key, value]
键值对的数组,它会根据给定数组创建一个对象:let prices = Object.fromEntries([
['banana', 1],
['orange', 2],
['meat', 4]
]);
// 现在 prices = { banana: 1, orange: 2, meat: 4 }alert(prices.orange);
// 2
我们可以使用
Object.fromEntries
从 Map
得到一个普通对象(plain object)。如果我们在 Map 中存储了一些数据,但是我们需要把这些数据传给需要普通对象的第三方代码。
let map = new Map();
map.set('banana', 1);
map.set('orange', 2);
map.set('meat', 4);
let obj = Object.fromEntries(map.entries());
// 创建一个普通对象(plain object)(*)// 完成了!
// obj = { banana: 1, orange: 2, meat: 4 }alert(obj.orange);
// 2
Set 是一个特殊的类型集合,没有键,它的每一个值只能出现一次。
主要方法如下:
new Set(iterable)
—— 创建一个set
,如果提供了一个iterable
对象(通常是数组),将会从数组里面复制值到set
中。set.add(value)
—— 添加一个值,返回 set 本身set.delete(value)
—— 删除值,如果value
在这个方法调用的时候存在则返回true
,否则返回false
。set.has(value)
—— 如果value
在 set 中,返回true
,否则返回false
。set.clear()
—— 清空 set。set.size
—— 返回元素个数。
set.add(value)
并不会发生什么改变。这就是 Set
里面的每一个值只出现一次的原因。例如,我们有客人来访,我们想记住他们每一个人。但是已经来访过的客人再次来访,不应造成重复记录。每个访客必须只被“计数”一次。
Set
可以帮助我们解决这个问题:let set = new Set();
let john = { name: "John" };
let pete = { name: "Pete" };
let mary = { name: "Mary" };
// visits,一些访客来访好几次
set.add(john);
set.add(pete);
set.add(mary);
set.add(john);
set.add(mary);
// set 只保留不重复的值
alert( set.size );
// 3for (let user of set) {
alert(user.name);
// John(然后 Pete 和 Mary)
}
Set
的替代方法可以是一个用户数组,用 arr.find 在每次插入值时检查是否重复。但是这样性能会很差,因为这个方法会遍历整个数组来检查每个元素。Set
内部对唯一性检查进行了更好的优化。Set 迭代(iteration) 使用 for…of 或 forEach 来遍历 Set
let set = new Set(["oranges", "apples", "bananas"]);
for (let value of set) alert(value);
// 与 forEach 相同:
set.forEach((value, valueAgain, set) => {
alert(value);
});
forEach
的回调函数有三个参数:一个 value
,然后是 同一个值 valueAgain
,最后是目标对象。没错,同一个值在参数里出现了两次。forEach
的回调函数有三个参数,是为了与 Map
兼容。当然,这看起来确实有些奇怪。但是这对在特定情况下轻松地用 Set
代替 Map
很有帮助,反之亦然。Map
中用于迭代的方法在 Set
中也同样支持:set.keys()
—— 遍历并返回所有的值(returns an iterable object for values),set.values()
—— 与set.keys()
作用相同,这是为了兼容Map
,set.entries()
—— 遍历并返回所有的实体(returns an iterable object for entries)[value, value]
,它的存在也是为了兼容Map
。
推荐阅读
- Vue.js|十二、Promise的学习笔记(Promise的基本使用、链式编程、all())
- 前端|【前端】利用JavaScript做打砖块小游戏
- js|手把手教你制作一个简单的聊天机器人(图灵api)
- java|如果再写for循环,我就锤自己
- vue|前端设置下拉框与选择
- vue|vue 的4种实现动画方式
- 5-JS-数据类型-Iterable object (可迭代对象)
- vue|vue个人在线简历
- vue3|While resolving: aidr-web-service-web@1.0.0 vue3安装依赖报错