1. map和object
Map | Object | |
---|---|---|
意外的键 | Map默认情况不包含任何键,只包含显式插入的键。 | Object 有一个原型, 原型链上的键名有可能和自己在对象上的设置的键名产生冲突。 |
键的类型 | Map的键可以是任意值,包括函数、对象或任意基本类型。 | Object 的键必须是 String 或是Symbol。 |
键的顺序 | Map 中的 key 是有序的。因此,当迭代的时候,Map 对象以插入的顺序返回键值。 | Object 的键是无序的 |
size | Map 的键值对个数可以轻易地通过size 属性获取 | Object 的键值对个数只能手动计算 |
迭代 | Map 是 iterable 的,所以可以直接被迭代。 | 迭代Object需要以某种方式获取它的键然后才能迭代。 |
性能 | 在频繁增删键值对的场景下表现更好。 | 在频繁添加和删除键值对的场景下未作出优化。 |
2. map 和 weakMap
(1)Map
map
本质上就是键值对的集合,但是普通的Object
中的键值对中的键只能是字符串。而ES6提供的Map数据结构类似于对象,但是它的键不限制范围,可以是任意类型,是一种更加完善的Hash结构。如果Map的键是一个原始数据类型,只要两个键严格相同,就视为是同一个键。
实际上Map是一个数组,它的每一个数据也都是一个数组,其形式如下:
const map = [
["name","张三"],
["age",18],
]
Map数据结构有以下操作方法:
**size**
:map.size
返回Map结构的成员总数。**set(key,value)**
:设置键名key对应的键值value,然后返回整个Map结构,如果key已经有值,则键值会被更新,否则就新生成该键。(因为返回的是当前Map对象,所以可以链式调用)**get(key)**
:该方法读取key对应的键值,如果找不到key,返回undefined。**has(key)**
:该方法返回一个布尔值,表示某个键是否在当前Map对象中。**delete(key)**
:该方法删除某个键,返回true,如果删除失败,返回false。**clear()**
:map.clear()清除所有成员,没有返回值。
Map结构原生提供是三个遍历器生成函数和一个遍历方法
keys()
:返回键名的遍历器。values()
:返回键值的遍历器。entries()
:返回所有成员的遍历器。forEach()
:遍历Map的所有成员。
const map = new Map([
["foo",1],
["bar",2],
])
for(let key of map.keys()){
console.log(key); // foo bar
}
for(let value of map.values()){
console.log(value); // 1 2
}
for(let items of map.entries()){
console.log(items); // ["foo",1] ["bar",2]
}
map.forEach( (value,key,map) => {
console.log(key,value); // foo 1 bar 2
})
(2)WeakMap
WeakMap 对象也是一组键值对的集合,其中的键是弱引用的。其键必须是对象,原始数据类型不能作为key值,而值可以是任意的。 该对象也有以下几种方法:
**set(key,value)**
:设置键名key对应的键值value,然后返回整个Map结构,如果key已经有值,则键值会被更新,否则就新生成该键。(因为返回的是当前Map对象,所以可以链式调用)**get(key)**
:该方法读取key对应的键值,如果找不到key,返回undefined。**has(key)**
:该方法返回一个布尔值,表示某个键是否在当前Map对象中。**delete(key)**
:该方法删除某个键,返回true,如果删除失败,返回false。
const wm1 = new WeakMap(),
wm2 = new WeakMap(),
wm3 = new WeakMap();
const o1 = {},
o2 = function() {},
o3 = window;
wm1.set(o1, 37);
wm1.set(o2, 'azerty');
wm2.set(o1, o2); // value 可以是任意值,包括一个对象或一个函数
wm2.set(o3, undefined);
wm2.set(wm1, wm2); // 键和值可以是任意对象,甚至另外一个 WeakMap 对象
wm1.get(o2); // "azerty"
wm2.get(o2); // undefined,wm2 中没有 o2 这个键
wm2.get(o3); // undefined,值就是 undefined
wm1.has(o2); // true
wm2.has(o2); // false
wm2.has(o3); // true (即使值是 undefined)
wm3.set(o1, 37);
wm3.get(o1); // 37
wm1.has(o1); // true
wm1.delete(o1);
wm1.has(o1); // false
其clear()方法已经被弃用,所以可以通过创建一个空的WeakMap并替换原对象来实现清除。 实现一个带有clear的weakMap
class ClearableWeakMap {
constructor(init) {
this._wm = new WeakMap(init);
}
clear() {
this._wm = new WeakMap();
}
delete(k) {
return this._wm.delete(k);
}
get(k) {
return this._wm.get(k);
}
has(k) {
return this._wm.has(k);
}
set(k, v) {
this._wm.set(k, v);
return this;
}
}
WeakMap的设计目的在于,有时想在某个对象上面存放一些数据,但是这会形成对于这个对象的引用。一旦不再需要这两个对象,就必须手动删除这个引用,否则垃圾回收机制就不会释放对象占用的内存。 而WeakMap的键名所引用的对象都是弱引用,即垃圾回收机制不将该引用考虑在内。因此,只要所引用的对象的其他引用都被清除,垃圾回收机制就会释放该对象所占用的内存。也就是说,一旦不再需要,WeakMap 里面的键名对象和所对应的键值对会自动消失,不用手动删除引用。
3. set 和 weakSet
(1)Set
Set 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。 Set有以下操作方法:
size
:返回 Set 对象中的值的个数add(value)
:在Set对象尾部添加一个元素。返回该 Set 对象。clear()
:移除Set对象内的所有元素。delete(value)
:移除值为value
的元素,并返回一个布尔值来表示是否移除成功。Set.prototype.has(value)
会在此之后返回false
。entries()
:返回一个新的迭代器对象,该对象包含 Set 对象中的按插入顺序排列的所有元素的值的[value, value]
数组。为了使这个方法和 Map 对象保持相似,每个值的键和值相等。foreach((value, key, set) => { /* ... */ )
:按照插入顺序,为 Set 对象中的每一个值调用一次callBackFn
。如果提供了thisArg
参数,回调中的this
会是这个参数。keys()
:与 values() 方法相同,返回一个新的迭代器对象,该对象包含 Set 对象中的按插入顺序排列的所有元素的值。values()
:返回一个新的迭代器对象,该对象包含 Set 对象中的按插入顺序排列的所有元素的值。has(value)
:返回一个布尔值,表示该值在 Set 中存在与否。
(2)WeakSet
WeakSet 对象是一些对象值的集合。且其与 Set 类似,WeakSet 中的每个对象值都只能出现一次。在 WeakSet 的集合中,所有对象都是唯一的。 WeakSet和 Set 对象的主要区别有:
- WeakSet 只能是对象的集合,而不能像 Set 那样,可以是任何类型的任意值。
- WeakSet 持弱引用:集合中对象的引用为弱引用。如果没有其它的对 WeakSet 中对象的引用,那么这些对象会被当成垃圾回收掉。
持有的方法:
add(value)
:在WeakSet
对象尾部添加一个元素。返回该WeakSet
对象。delete(value)
:移除值为value
的元素,并返回一个布尔值来表示是否移除成功。WeakSet.prototype.has(value)
会在此之后返回false
。has(value)
:返回一个布尔值,表示该值在WeakSet
中存在与否。