作为 ES2015 的新增特性,Set 和 Map 对象大家应该很熟悉了,例如 Set 在数组去重等场景中经常会用到:
function unique(array = []) {
return Array.from(new Set(array));
}
但是一般我们都是只在需要这种数据结构的时候才去创建它,在用完之后就转回数组。大家可能都认为,相比 Set 、Map 对象,还是数组操作更熟悉一些。但实际上它们本身也提供了一些遍历方法,下面我们一起来看下。
Set 对象遍历操作
Set 结构的实例有四个遍历方法,可以用于遍历成员:
Set.prototype.keys() :返回键名的遍历器Set.prototype.values() :返回键值的遍历器Set.prototype.entries() :返回键值对的遍历器Set.prototype.forEach() :使用回调函数遍历每个成员
需要特别指出的是,Set 的遍历顺序就是插入顺序。这个特性有时非常有用,比如使用 Set 保存一个回调函数列表,调用时就能保证按照添加顺序调用。
与数组类似,Set 对象也提供 keys 、values 、entries 方法返回一个迭代器。与数组不同的是,Set 对象 没有键名,只有键值(或者说键名和键值是同一个值),所以 keys 方法和 values 方法的行为完全一致。
let set = new Set(['red', 'green', 'blue']);
for (let item of set.keys()) {
console.log(item);
}
for (let item of set.values()) {
console.log(item);
}
下面的代码中,entries 方法返回的遍历器,同时包括键名和键值,所以每次输出一个数组,它的两个成员完全相等:
let set = new Set(['red', 'green', 'blue']);
for (let item of set.entries()) {
console.log(item);
}
Set 结构的实例默认可遍历,它的默认遍历器生成函数就是它的 values 方法。
Set.prototype[Symbol.iterator] === Set.prototype.values
一个对象只要实现了 Symbol.iterator 接口,就是一个可迭代对象,可以使用 for...of 遍历,或者使用扩展运算符展开
这意味着,可以省略 values 方法,直接用 for...of 循环遍历 Set 。
let set = new Set(['red', 'green', 'blue']);
for (let x of set) {
console.log(x);
}
数组扩展运算符内部使用 for...of 循环,所以也可用于 Set 结构
Set 结构的实例与数组一样,也拥有 forEach 方法,用于对每个成员执行某种操作,没有返回值。
et set = new Set([1, 4, 9]);
set.forEach((value, key) => console.log(key + ' : ' + value))
上面代码说明,forEach 方法的参数就是一个处理函数。该函数的参数与数组的 forEach 一致,依次为键值、键名、集合本身(上例省略了该参数)。这里需要注意,Set 结构的 键名就是键值(两者是同一个值),因此第一个参数与第二个参数的值永远都是一样的。
这里可以得出一个结论,Set 对象 forEach 的回调只需要接受一个形参即可
Map 对象遍历操作
Set 对象大家都知道使用扩展运算符转为数组去遍历,这样其实也没啥问题,但是 Map 对象的遍历就五花八门了,有的用扩展运算符转数组遍历,还有的用 Object.fromEntries 转为对象去遍历:
const map = new Map([["name", 1], ["age", 2]]);
[...map].forEach(([key, val]) => {
})
const obj = Object.fromEntries(map);
for (let key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
}
}
这边推荐使用第一种方法,直接遍历数组简单直接,不用担心遍历到对象原型上
实际上 Map 对象也提供了一些用于遍历的方法,下面我们来看下。
Map 结构原生提供三个遍历器生成函数和一个遍历方法。
Map.prototype.keys() :返回键名的遍历器。Map.prototype.values() :返回键值的遍历器。Map.prototype.entries() :返回所有成员的遍历器。Map.prototype.forEach() :遍历 Map 的所有成员。
需要特别注意的是,Map 的遍历顺序就是插入顺序。
使用 keys 和 values :
const map = new Map([
['F', 'no'],
['T', 'yes'],
]);
for (let key of map.keys()) {
console.log(key);
}
for (let value of map.values()) {
console.log(value);
}
使用 entries :
for (let item of map.entries()) {
console.log(item[0], item[1]);
}
for (let [key, value] of map.entries()) {
console.log(key, value);
}
Map 结构的默认遍历器接口(Symbol.iterator 属性)是 entries 方法。
map[Symbol.iterator] === map.entries
这意味着 Map 结构可以直接使用 for...of 遍历:
for (let [key, value] of map) {
console.log(key, value);
}
顺便提一下,用扩展运算符将 Map 结构转为数组,实际上就是 for...of 调用 entries 方法返回的迭代器:
const map = new Map([
[1, 'one'],
[2, 'two'],
[3, 'three'],
]);
[...map]
[...map.entries()]
[...map.keys()]
[...map.values()]
此外,Map 还有一个 forEach 方法,与数组的 forEach 方法类似,也可以实现遍历。
map.forEach(function(value, key, map) {
console.log("Key: %s, Value: %s", key, value);
});
参考
Set 和 Map 数据结构 - 阮一峰 ES6 教程
|