最近在项目中用到了Set,顺便复习了一下Set的基本API,因为Map和Set很多地方是相通的,所以顺便把Map也带上,本文只介绍基本API,这两个对象在我在项目中用的很少,至于用它们实现私
1.Map Map是一种新的集合类型,与Object类型相似,它为js带来了真正的键/值存储机制,够保将 任意类型 的值以存键/值对的形式按顺序保存。 在Map中键值是否相等采用的是类似于严格相等(===)方式来判断,但值得注意的是,在Map中认为NaN与NaN是相等的,尽管实际上NaN ! NaN。 Map与Object的差异,以下表格内容来自此处
创建Map集合映射 在初始化时,传入一个可迭代的对象,并且包含键值对的数组,数组的第一个值是键,第二个值是值,这个可迭代的数组对象每一组键值对都会按顺序添加到新映射中。
const Map1 = new Map([['a', 1], ['b', 2]])
console.log(Map1); //Map(2) {'a' => 1, 'b' => 2}
Map的api
- Map.prototype.set(key,value)
Map1.set('key1', 'value1').set('key2', 'value2')
console.log(Map1) //Map(4) {'a' => 1, 'b' => 2, 'key1' => 'value1', 'key2' => 'value2'}
- Map.prototype.has(key)
console.log(Map1.has('a')); //true
console.log(Map1.has('c')); //false
- Map.prototype.get(key)
console.log(Map1.get('a')); // 1
console.log(Map1.get('c')); // undefined
- Map.prototype.size
console.log(Map1.size); //4
- Map.prototype.delete(key)
console.log(Map1.delete('c')); //false
console.log(Map1.delete('a')); //true
console.log(Map1); // {'b' => 2, 'key1' => 'value1', 'key2' => 'value2'}
- Map.prototype.clear()
Map1.clear()
console.log(Map1) //Map(0) {size: 0}
注意:当引用类型作为Map的键或者值的话,我们修改引用的键或值,Map中的映射关系不会改变,
const Map2 = new Map()
const key1Obj = { key1: 'key1' }
const value1Obj = { value1: 'value1' }
const keyArr = ['key1']
const ValueArr = ['value1']
Map2.set(key1Obj, value1Obj).set(keyArr, ValueArr)
console.log(Map2); // {{key1: "key1"} => {value1: 'value1'}, ['key1']=> ['value1']}
key1Obj.key2 = 'key2'
ValueArr.push('value2')
console.log(Map2); // {{key1: "key1",key2:"key2"} => {value1: 'value1'}, ['key1']=> ['value1','value2']}
Map的迭代方式
Map映射实例可以提供一个迭代器(Iterator)能以插入顺序生成[key, value]形式的数组,因此Map是可以遍历的。可以通过 entries()方法(或者 Symbol.iterator 属性)取得这个迭代器。
Map.prototype.entries() === Map.prototype@@iterator
- for... of
const Map3 = new Map([['key1', 'value1'], ['key2', 'value2'], ['key3', 'value3']])
for (let el of Map3.entries()) {
console.log(el); // ['key1', 'value1'] ['key2', 'value2'] ['key2', 'value2']
}
for (let el of Map3[Symbol.iterator]()) {
console.log(el); // ['key1', 'value1'] ['key2', 'value2'] ['key2', 'value2']
}
Map.prototype.forEach(callback(value,key,map),thisArg)
- Map.forEach()接受两个参数,第一个参数是一个回调函数,该回调函数接收三个可选值,第一个值value是每个迭代的值,第一个值key是每个迭代的键,第三个值map是要迭代的Map对象。第二个参数thisArg用于指定回调函数中this的值
Map3.forEach((value, key) => {
console.log(key); //key1 ,key2,key3
console.log(value); //value1 ,value2 ,value3
})
如果只想遍历Map的值或键,可以调用values()或keys()方法,这两个方法分别返回以插入顺序生成值或键的迭代器
for (let key of Map3.keys()) {
console.log(key); //kye1 key2 key3
}
for (let key of Map3.values()) {
console.log(key); //value1 value2 value3
}
注意:如果迭代的键或者值不是引用类型,那么在迭代过程中是不可修改的,如果是引用类型的值或者键,修改后映射关系不会改变
const Map4 = new Map([['key1', 'value1']])
for (let key of Map4.keys()) {
key = 'newKey'
console.log(Map4.get('newKey')); //undefined
console.log(Map4.get('key1')); //value1
}
const keyObj = { a: '1' }
const valueObj = { value: 'val' }
const Map5 = new Map([
[keyObj, valueObj]
])
for (let key of Map5.keys()) {
key.a = '2'
key.b = '3'
console.log(key); //{a:'2',b:'3' }
console.log(Map5.get(keyObj)); //{ value: 'val' }
}
console.log(Map5); // {a:'2',b:'3' } => { value: 'val' }
for (let value of Map5.values()) {
value.value = '2'
value.newVal = 'newVal'
console.log(Map5.get(keyObj)); //{value: '2', newVal: 'newVal'} 修改成功
}
console.log(Map5); //{a: '2', b: '3'} =>{value: '2', newVal: 'newVal'} 修改成功
2.WeakMap
WeakMap是Map的“兄弟”类型,其 API 也是 Map 的子集,WeakMap对象是一组键/值对的集合,其中的键是弱引用的。其键必须是对象,而值可以是任意的。
WeakMap的API
- WeakMap.prototype.set(key,value)
- WeakMap.prototype.has(key)
const WMap1 = new WeakMap()
const key1 = {}
const key2 = {}
WMap1.set(key1, 'value1')
console.log(WMap1.has(key1)); //true
console.log(WMap1.has(key2)); //false
- WeakMap.prototype.get(key)
console.log(WMap1.get(key1)); //value1
console.log(WMap1.get(key2)); //undefined
- WeakMap.prototype.delete(key)
console.log(WMap1.delete(key1)); //true 删除成功
console.log(WMap1.delete(key)); //false 因为WMap1中已经不存在key1,所以返回false
3.Set Set和Map很像,都是ECMAScript6新增的一种新的集合类型,大多数API和行为都是共有的,Set最大的特点是Set对象允可以存储任何类型唯一值,无论是原始值或者是对象引用,并且会自动去重,使集合里面的值具有唯一性,用来去重很方便。 创建Set对象,在Set在判断对象子项是否相等是采用的是严格相等,特别注意的是,在Set集合中,NaN被判断为相等
const set1 = new Set(['1', '2', 2, '3', '3', 2])
console.log(set1);//Set(4) {'1', '2', 2, '3'}
const set2 = new Set([null, undefined, null, undefined,NaN,NaN])
console.log(set2); //Set(3) {null, undefined,NaN}
Set的API
- Set.prototype.add(value)
const set3 = new Set()
set3.add(1);
set3.add(2).add(3)
console.log(set3); //Set(3) {1, 2, 3}
- Set.prototype.has(value)
console.log(set3.has(3)); // true
console.log(set3.has(4)); //false
- Set.prototype.size
console.log(set3.size); // 3
- Set.prototype.delete(value)
console.log(set3.delete(4)); //false
console.log(set3.delete(3)); //true
console.log(set3); //Set(2) {1, 2}
- Set.prototype.clear()
set3.clear()
console.log(set3); //Set(0) {size: 0}
Set的迭代方式
Set实例也可以提供一个迭代器(Iterator),能以插入顺序生成集合内容。可以通过 values()方法及其别名方法 keys()(或者 Symbol.iterator 属性,它引用 values())取得这个迭代器:
- for ... of
const set4 = new Set([1, 2, 3, 4, 5, 6, 7])
for (const el of set4.values()) {
console.log(el); //1, 2, 3, 4, 5, 6, 7
}
for (const el of set4.keys()) {
console.log(el); //1, 2, 3, 4, 5, 6, 7
}
for (const el of set4[Symbol.iterator]()) {
console.log(el); //1, 2, 3, 4, 5, 6, 7
}
//以上三种方式等价
// Set对象还有个 entries()方法,可以按照插入顺序产生包含两个元素的数组,这两个元素是集合中每个值的重复值
for (const el of set4.entries()) {
console.log(el); //[1,1], [2,2], [3,3], [4,4], [5,5],[6,6] , [7,7]
}
- Set.prototype.forEach(callback(value,key,set),thisArg)
set4.forEach((value1, value2) => {
console.log('value1:' + value1, 'value2:' + value2);
})
//value1:1 value2:1
//value1:2 value2:2
//value1:3 value2:3
//value1:4 value2:4
//value1:5 value2:5
//value1:6 value2:6
//value1:7 value2:7
注意 :如果迭代值是值类型,那么在迭代过程中原来对象的值不会可修改,如果是引用类型的值则可以修改,这点和Map一样
4.WeakSet
WeakSet是Set 的“兄弟”类型,其 API 也是 Set 的子集。WeakSet 中的“weak”(弱),描述的是 JavaScript 垃圾回收程序对待“弱集合”中值的方式。
WeakSet与Set的区别
1.弱集合中的值只能是 Object 或者继承自 Object 的类型 ,不能是其他类型,只要有任意类型不是Object,那么初始化就会失败
2.弱集合对其元素都是弱引用,当其引用的值为空时,就会被销毁触发垃圾回收机制
3.弱集合对其元素随时都可能被销毁,所以不可遍历
创建 WeakSet集合,必须传入可迭代集合,null类型被认为是undefined。
const WSet1 = new WeakSet([{ a: '1' }])
- WeakSet.prototype.add(value)
- WeakSet.prototype.has(value)
const WSet2 = new WeakSet()
const value1 = {name:'张三'}
const value2 = {name:'李四'}
WSet2.add(value1 )
WSet2.has(value1 )//true
WSet2.has(value2) //false
- WeakSet.prototype.delete(value)
WSet2.delete(value1 )//true // 删除成功
WSet2.delete(value1) //false //因为已经删除,所以对象在不存在,再次删除失败