# 定义 (opens new window)
- 字典
- 一些元素的集合,每个元素都有一个称作key的域,不同元素的key各不相同
- 集合
- 由一堆无序的、相关联的,且不重复的内存结构组成的组合
- 区别
- 共同点: 集合、字典都可以存储不重复的值
- 不同点: 集合以[值、值]形式存储,字典以['键', '值']形式存储
# Map
- 是一种字典数据结构
- 是键值对的有序列表,而键和值都可以是任意类型
- 本身是一个构造函数,用于生成Map数据结构
- 增删改查
size/set()/get()/has()/delete()/clear()
set()
设置键名key对应的键值
value
,返回整个Map结构如果
key
已经有值,则value
会被更新,否则新生成键值对,并返回整个Map可链式调用
const map = new Map() // 键和值都可以是**任意类型** map.set('str', 6) map.set(666, 'Hello') map.set(undefined, {name: 1111}) // 链式调用 map.set(1, 'a').set(2, 'b').set(3, 'c')
get()
读取key
对应的键值,找不到则返回undefined
const map = new Map() const fn = function() {console.log('hello')} map.set(fn, 'HELLO ES6') // 键可以是函数 map.get(fn) // 'HELLO ES6'
has()
返回一个布尔值,表示某个键是否在当前Map中const map = new Map() map.set('str', 6) map.set(666, 'Hello') map.set(undefined, {name: 1111}) map.has('str') // true map.has(666) // true map.has(undefined) // true map.has('fuck') // false
delete()
删除某个键。成功返回true
,反之亦然。const map = new Map() map.set(undefined, 'nono') map.has(undefined) // true map.delete(undefined) // true map.has(undefined) // false
clear()
清空所有成员,没有返回值const map = new Map() map.set('foo', true) map.set('bar', 111) map.size // 2 map.clear() map.size // 0
size
属性返回Map结构的成员总数, 类似array.length
const map = new Map() map.set('foo', true) map.set('bar', false) map.size // 2
遍历(遍历顺序为插入顺序)
keys()
: 返回键名遍历器values()
: 返回键值的遍历器entries()
: 返回键值对的遍历器forEach()
: 只用回调函数遍历每个成员
const map = new Map([['f', 'oo'], ['b', 'ar']]) for (let key of map.keys()) { console.log(key) } // 'f' // 'b' for (let val of map.values()) { console.log(val) } // 'oo' // 'ar' // 以下三个方法相等 for (let item of map.entries()) { console.log(item[0], item[1]) } for (let [key, val] of map.entries()) { console.log(key, val) } for (let [key, val] of map) { console.log(key, val) } // 'f', 'oo' // 'b', 'ar' map.forEach((val, key, map) => { console.log('key: ', key, 'val: ', val) }) // key: f val: oo // key: b val: ar
# Set
- 是一种集合数据结构
- 类似数组,但成员的值都是唯一的,没有重复,一般称为集合
- 本身是一个构造函数,用于生成Set数据结构
- 增删改查
add()/delete()/has()/clear()
add()
添加某个值,返回Set,只处理未添加的值const s = new Set() s.add(1).add(2).add(2) // 2只会被添加一次
delete()
删除某个值,返回布尔值表示是否删除成功s.delete(1)
has()
返回一个布尔值,表示该值是否为Set的成员s.has(1)
clear()
清空所有成员,没有返回值s.clear()
遍历(遍历顺序为插入顺序)
keys()
: 返回键名遍历器values()
: 返回键值的遍历器entries()
: 返回键值对的遍历器forEach()
: 只用回调函数遍历每个成员
// keys values entries返回的欧式遍历器对象 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'] //forEach用于处理每个元素,没有返回值。键名键值都相等。第二个参数用于绑定处理函数的this set.forEach((val, key) => console.log(key + ':' + val)) // red:red // green:green // blue:blue
# 应用
- 结合扩展运算符去重
// 字符串
let str = '35225'
let unique = [...new Set(str)].join('')
// '352'
// 数组
let arr = ['3', '5', '5']
let unique = [...new Set(arr)]
// ['3', '5']
- 实现并集、交集和差集
let a = new Set([1, 2, 3])
let b = new Set([4, 3, 2])
// 并集
let union = new Set([...a, ...b]) // Set(4) {1, 2, 3, 4}
//交集
let intersect = new Set([...a].filter(x => b.has(x))) // Set(2) {2, 3}
// 差集
let diff = new Set([...a].filter(x => !b.has(x))) // Set(1) {1}
# WeakMap&WeakSet
WeakMap
- 只接受对象作为键名(
null
除外) - 与
Map
区别- 没有遍历操作的API
- 没有
clear()
const wm = new WeakMap() wm.set('foo', 1) // Uncaught TypeError: Invalid value used as weak map key const key = {foo: 1} wm.set(key, 1) wm.get(key) // 1 // 数组也可 const a1 = [1, 2, 3] const a2 = [4, 5, 6] wm.set(a1, a2) wm.get(a1) // [4, 5, 6] const wm2 = new WeakMap([[a1, 'foo'], [a2, 'bar']]) wm.get(a1) // 'foo'
- 键名所指的对象,一旦不再需要,里面的键名对象和所对应的键值对会自动消失,不用手动删除引用
const wm = new WeakMap() let key = {'foo': 1} wm.set(key, 1) // WeakMap {{…} => 1} wm.get(key) // 1 key = null wm.get(key) // undefined // 在网页的 DOM 元素上添加数据,就可以使用WeakMap结构,当该 DOM 元素被清除,其所对应的WeakMap记录就会自动被移除 const wm = new WeakMap(); const element = document.getElementById('example'); wm.set(element, 'some information'); wm.get(element) // "some information"
- WeakMap弱引用的只是键名,不是键值。键值依然正常引用,不会影响键值
const wm = new WeakMap() let key = {} let obj = {'foo': 1} wm.set(key, obj) obj = null wm.get(key) // {foo: 1}
- 只接受对象作为键名(
WeakSet
- 成员只能是引用类型
- 接受一个具有
Iterable
接口的对象作为参数 - 与
Set
区别- 没有遍历操作的API
- 没有
size
const ws = new WeakSet([1, 2]) // Uncaught TypeError: Invalid value used in weak set let obj1 = {foo: 1} let obj2 = {bar: 2} const ws = new WeakSet([obj1, obj2]) /* WeakSet {{…}, {…}} [[Entries]] 0: value: {foo: 1} 1: value: {bar: 2} [[Prototype]]: WeakSet */
# 扩展知识点
Map
和Object
的区别Map
是纯净的,只含有显示插入的键。Object
会有原型上的属性和方法(ES5后可通过Object.create(null)
创建一个纯净对象)Map
的key
可以是Js支持的所有数据类型。Object
的key
必须是简单数据类型(整数、字符串、Symbol)Map
有序,迭代时会按照插入顺序返回键值。Object
无序Map
长度可以通过size获取。Object
需要通过Object.key(obj).length
Map
可迭代。Object
得通过获取键来迭代Map
通过get()
访问。Object
通过./[]
访问Map
通过has()
判断元素是否存在。Object
通过obj.key === undefined || 'key' in obj || Object.prototype.hasOwnProperty()
Map
通过set()
新增数据。Object
通过obj['key'] = val || obj.key = val
Map
通过delete
删除数据。Object
通过非原生方法delete obj.id || obj.id = undefined
, 第二种方式只是把值设为undefined
,属性仍在Map
继承自Object
- 如何选择?
使用
Object
的情况- 存储简单数据类型,且key都为简单数据类型时用
Object
, 创建方式更高效 - 需要在单独的逻辑钟访问属性或元素时候用
Object
var obj = { id: 1, name: "It's Me!", print: function(){ return `Object Id: ${this.id}, with Name: ${this.name}`; } } console.log(obj.print())
JSON
支持Object
,但不支持Map
- 存储简单数据类型,且key都为简单数据类型时用
使用
Map
的情况Map
在存储大量数据的时候性能更好,特别在执行代码时不知道key的情况下Map
会保持元素插入顺序,Object
不行- 删除操作频繁的情况下使用
Map
,Map
是纯粹的hash
,Object
存在一起内部逻辑,使用delete
会有性能问题。