【09】ES6:Set 和 Map 数据结构

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

一、Set

1、基本语法

定义

Set 是一系列无序、没有重复值的数据集合。数组是一系列有序下标索引的数据集合。

Set 本身是一个构造函数用来生成 Set 数据结构。

const s = new Set()
[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x))

for (let i of s) {
	console.log(i)
}
// 2 3 5 4 // Set 中不能有重复的成员

参数

Set 函数可以接受一个数组或者具有 iterable 接口的其他数据结构作为参数用来初始化。

// 数组作为参数
const s = new Set([1, 2, 1])
console.log(s) // Set(2) { 1, 2 }

// 字符串作为参数
const s = new Set('hiii')
console.log(s) // Set(2) { 'h', 'i' }

// arguments 作为参数
function func() {
	console.log(new Set(arguments))
}
func(1, 2, 1) // Set(2) { 1, 2 }

// NodeList 作为参数
new Set(document.querySelectorAll('P'))

// Set 作为参数这也是复制一个 Set 的方法
const s = new Set([1, 2, 1])
console.log(new Set(s)) // Set(2) { 1, 2 }
console.log(s) // Set(2) { 1, 2 }

注意事项

Set 对重复值的判断基本遵循严格相等===。

但是对于 NaN 的判断与 === 不同Set 中 NaN 等于 NaN 。

2、Set 实例的方法和属性

【Set 实例的属性】

属性说明
Set.prototype.constructor构造函数默认就是 Set 函数。
Set.prototype.size返回 Set 实例的成员总数。
const s = new Set()
s.add(0)
s.add(1).add(2).add(2).add(3)

s.size // 4

【Set 实例的方法】

操作方法用于操作数据说明
Set.prototype.add(value)添加某个值返回 Set 结构本身。
Set.prototype.delete(value)删除某个值返回一个布尔值表示删除是否成功。
Set.prototype.has(value)返回一个布尔值表示该值是否为Set的成员。
Set.prototype.clear()清除所有成员没有返回值。
const s = new Set()
s.add(0)
s.add(1).add(2).add(2).add(3) // 可以连写
s // Set(4) { 0, 1, 2, 3 }

s.has(1) // true
s.has(4) // false

s.delete(2)
s.delete(4) // 使用 delete 删除不存在的成员什么都不会发生也不会报错
s // Set(3) { 0, 1, 3 }

s.clear()
s // Set(0) {}
遍历方法用于遍历成员说明
Set.prototype.keys()返回键名的遍历器。
Set.prototype.values()返回键值的遍历器。
Set.prototype.entries()返回键值对的遍历器。
Set.prototype.forEach()使用回调函数遍历每个成员。

keys 方法、values 方法、entries 方法返回的都是遍历器对象。 由于 Set 结构没有键名只有键值所以 keys 方法和 values 方法的行为完全一致。

Set 结构的实例与数组一样也拥有 forEach 方法用于对每个成员执行某种操作没有返回值。

let set = new Set(['red', 'green', 'blue'])

for (let item of set.keys()) {
	console.log(item)
}
// red green blue

for (let item of set.values()) {
  console.log(item)
}
// red green blue

for (let item of set.entries()) {
  console.log(item)
}
// ['red', 'red'] ['green', 'green'] ['blue', 'blue']

let set = new Set([1, 4, 9])
set.forEach((value, key) => console.log(key + ' : ' + value))
// 1 : 1
// 4 : 4
// 9 : 9

Set 结构的实例默认可遍历它的默认遍历器生成函数就是它的 values 方法。

这意味着可以省略 values 方法直接用 for...of 循环遍历 Set。

Set.prototype[Symbol.iterator] === Set.prototype.values // true

let set = new Set(['red', 'green', 'blue'])
for (let x of set) {
	console.log(x)
}
// red green blue

3、Set 的应用

数组去重

扩展运算符...内部使用 for...of 循环所以也可以用于 Set 结构。

[...new Set(array)]

let arr = [3, 5, 2, 2, 5, 5]
let unique = [...new Set(arr)]
// [3, 5, 2]

Array.from() 方法可以将 Set 结构转为数组。

// Array.from 将类数组对象array-like和可遍历的对象iterable转换为真正的数组进行使用
function dedupe(array) {
	return Array.from(new Set(array))
}

dedupe([1, 1, 2, 3]) // [1, 2, 3]

字符串去重

[...new Set(str)].join('')

[...new Set('ababbc')].join('') // 'abc'

存放 DOM 元素

 // 这里使用 Set 是因为我们不需要通过下标去访问只需直接遍历即可
const s = new Set(document.querySelectorAll('p'))
s.forEach(function (elem) {
	elem.style.color = 'red'
})

遍历

数组的 mapfilter 方法也可以间接用于 Set 了。

let set = new Set([1, 2, 3])
set = new Set([...set].map(x => x * 2))
// 返回Set结构{2, 4, 6}

let set = new Set([1, 2, 3, 4, 5])
set = new Set([...set].filter(x => (x % 2) == 0))
// 返回Set结构{2, 4}

因此使用 Set 可以很容易地实现并集Union、交集Intersect和差集Difference。

let a = new Set([1, 2, 3])
let b = new Set([4, 3, 2])

// 并集
let union = new Set([...a, ...b])
// Set {1, 2, 3, 4}

// 交集
let intersect = new Set([...a].filter(x => b.has(x)))
// set {2, 3}

// a 相对于 b 的差集
let difference = new Set([...a].filter(x => !b.has(x)))
// Set {1}

二、Map

1、基本语法

定义

Map 可以理解为“映射”。Map 和 对象 都是键值对的集合。

Map 和 对象 的区别

对象一般用字符串当作 “键”当然在书写时字符串键的引号可以去掉。

Map 中的 “键” 可以是一切类型。

// 键 ——> 值key ——> value
// 对象
const person = {
	name: 'alex',
	age: 18
}

// Map
const m = new Map()
m.set('name', 'alex')
m.set('age', 18)
console.log(m) // Map(2) { 'name' => 'alex', 'age' => 18 }

// Map 中的 “键” 可以是一切类型。
const m = new Map()
m.set(true, 'true')
m.set({}, 'object')
m.set(new Set([1, 2]), 'set')
m.set(undefined, 'undefined')
console.log(m)
/*
Map(4) {
  true => 'true',
  {} => 'object',
  Set(2) { 1, 2 } => 'set',
  undefined => 'undefined'
}
*/

参数

任何具有 Iterator 接口、且每个成员都是一个双元素的数组的数据结构都可以当作 Map 构造函数的参数

例如二维数组、Set、Map 等

new Map([
	['name', 'alex'],
	['age', 18]
]) // Map(2) { 'name' => '张三', 'age' => 18 }

// 等价于
const items = [
	['name', 'alex'],
	['age', 18]
]
const map = new Map()
items.forEach(
	([key, value]) => map.set(key, value)
)
// Set
// Set 中也必须体现出键和值
const s = new Set([
	['name', 'alex'],
	['age', 18]
])
console.log(new Map(s)) // Map(2) { 'name' => 'alex', 'age' => 18 }
console.log(s) // Set(2) { [ 'name', 'alex' ], [ 'age', 18 ] }



// Map
const m = new Map([
	['name', 'alex'],
	['age', 18]
])
console.log(m) // Map(2) { 'name' => 'alex', 'age' => 18 }
const m2 = new Map(m) // Map 复制的方法
console.log(m2, m2 === m) // Map(2) { 'name' => 'alex', 'age' => 18 } false

注意事项

在 Set 中遇到重复的值直接去掉后者而 Map 中遇到重复的键值则是后面的覆盖前面的。

基本遵循严格相等===Map 中 NaN 也是等于 NaN。

2、Map 实例的方法和属性

【Map实例的属性】

属性说明
Map.prototype.constructor构造函数默认就是 Map 函数。
Map.prototype.size返回 Map 实例的成员总数
const map = new Map()
map.set('foo', true)
map.set('bar', false)

map.size // 2

【Map实例的操作方法】

操作方法用于操作数据说明
Map.prototype.set(key, value)设置键名 key 对应的键值为 value然后返回整个 Map 结构。
Map.prototype.get(key)读取 key 对应的键值如果找不到 key返回 undefined。
Map.prototype.delete(key)删除某个值返回一个布尔值表示删除是否成功。
Map.prototype.has(key)返回一个布尔值表示某个键是否在当前 Map 对象之中。
Map.prototype.clear()清除所有成员没有返回值。
const m = new Map()
m.set('edition', 6)        // 键是字符串
m.set(262, 'standard')     // 键是数值
m.set(undefined, 'nah')    // 键是 undefined
m.has('edition')     // true
m.has('years')       // false
m.has(262)           // true
m.has(undefined)     // true

// set 方法返回的是当前的 Map 对象因此可以采用链式写法。
let map = new Map()
  .set(1, 'a')
  .set(2, 'b')
  .set(3, 'c')


const m = new Map()
const hello = function() {console.log('hello');}
m.set(hello, 'Hello ES6!') // 键是函数
m.get(hello)  // Hello ES6!


const m = new Map();
m.set(undefined, 'nah')
m.has(undefined)     // true
m.delete(undefined)
m.has(undefined)       // false

let map = new Map()
map.set('foo', true)
map.set('bar', false)
map.size // 2
map.clear()
map.size // 0

【Map实例的遍历方法】

遍历方法用于遍历成员说明
Map.prototype.keys()返回键名的遍历器。
Map.prototype.values()返回键值的遍历器。
Map.prototype.entries()返回所有成员的遍历器。
Map.prototype.forEach()遍历 Map 的所有成员。

需要特别注意的是Map 的遍历顺序就是插入顺序。

const map = new Map([
	['F', 'no'],
	['T',  'yes']
])


for (let key of map.keys()) {
	console.log(key)
}
// F T


for (let value of map.values()) {
	console.log(value)
}
// no yes


for (let item of map.entries()) {
	console.log(item[0], item[1])
}
// F no   T yes

// 或者
for (let [key, value] of map.entries()) {
	console.log(key, value)
}
// F no   T yes


map.forEach(function(value, key, map) {
	console.log(value, key, map)
})
// no F Map(2) {'F' => 'no', 'T' => 'yes'}
// yes T Map(2) {'F' => 'no', 'T' => 'yes'}

Map 结构的默认遍历器接口Symbol.iterator属性就是 entries 方法。 这意味着可以省略 entries 方法。

map[Symbol.iterator] === map.entrie // true

// 等同于使用 map.entries()
for (let [key, value] of map) {
	console.log(key, value)
}
// F no   T yes

3、与其他数据结构的互相转换

Map 转为数组

const map = new Map()
	.set(true, 7)
	.set({foo: 3}, ['abc'])

[...map.keys()] // [ true,  { foo: 3 } ]
[...map.values()] // [ 7, [ 'abc' ] ]
[...map.entries()] // [ [ true, 7 ], [ { foo: 3 }, [ 'abc' ] ] ]
[...map] // [ [ true, 7 ], [ { foo: 3 }, [ 'abc' ] ] ]

// 转为数组后数组的 map 和 filter 方法也可以间接用于 Map

数组 转为 Map

new Map([
	[true, 7],
	[{foo: 3}, ['abc']]
]) 
// Map { true => 7, Object {foo: 3} => ['abc'] }

Map 转为对象

如果所有 Map 的键都是字符串它可以无损地转为对象。

如果有非字符串的键名那么这个键名会被转成字符串再作为对象的键名。

function strMapToObj(strMap) {
	let obj = Object.create(null)
	for (let [k, v] of strMap) {
		obj[k] = v
	}
	return obj
}

const myMap = new Map()
	.set('yes', true)
	.set('no', false)
strMapToObj(myMap) // { yes: true, no: false }

对象转为 Map

let obj = { a: 1, b: 2 }
let map = new Map(Object.entries(obj))

// 自己封装实现
function objToStrMap(obj) {
	let strMap = new Map()
	for (let k of Object.keys(obj)) {
		strMap.set(k, obj[k])
	}
	return strMap
}

objToStrMap({yes: true, no: false}) // Map {yes => true, no => false}

4、应用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<p>1</p>
<p>2</p>
<p>3</p>
<script>
	const [p1, p2, p3] = document.querySelectorAll('p')
    const m = new Map([
        [p1, {
            color: 'red',
            backgroundColor: 'yellow',
            fontSize: '40px'
        }],
        [p2, {
            color: 'green',
            backgroundColor: 'pink',
            fontSize: '40px'
        }],
        [p3, {
            color: 'blue',
            backgroundColor: 'orange',
            fontSize: '40px'
        }]
    ]);
    m.forEach((propObj, elem) => {
        for (const p in propObj) {
            elem.style[p] = propObj[p];
        }
    })	// 由于不需要改变 this 指向所以可以使用箭头函数
</script>
</body>
</html>
阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

“【09】ES6:Set 和 Map 数据结构” 的相关文章

Python语法实例代码分析 - 开发技术

这篇文章主要介绍了Python语法实例代码分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Python语法实例代码分析文章都会有所收获,下面我们一起来看看吧。执行 Python 语法正如我们在上一节中学习到的,可以直接在命令行中编写执行...

XML解析

int START_DOCUMENT=0; int END_DOCUMENT=1; int START_TAG=2; int END_TAG=3; int TEXT=4;...

接口幂等性的几种简单解决方案-CSDN博客

1、接口幂等性是什么 接口幂等性并不是数学中的幂等,而是对于用户来说不论网络波动或者刷新页面后重新操作某个动作等,最终导致对同一接口产生多次请求, 但是对于用户而言并没有产生影响。也就是说重复多次操作的结果 = 一次操作的结果。 2、有哪些常见的...

包裹函数

包裹函数:程序通常会检测调用是否正确,如果出输会将错误信息输出.包裹函数就是在完成实际的函数调用,检查返回值,并在发生错误时终止进程.约定包裹函数名是实际函数名的首字母大写形式 bool fun(int i); bool Fun(int i)//Fun包裹了...

选择控制循环

def fun(num): num = num*100; print '%d' % int(num); while(num>0): if(num>=25): print '%d (25)' % int(num/25);...

Navicat连接MySQL提示1045错误怎么解决 - 开发技术

这篇文章主要讲解了“Navicat连接MySQL提示1045错误怎么解决”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Navicat连接MySQL提示1045错误怎么解决”吧!错误提示:1045-Access deni...