Set
是一种类似数组的对象,但成员值唯一。
// 不会添加重复的值
let set = new Set(); // {}
set.add('test'); // {'test'}
set.add('test'); // {'test'}
// 接受具有 iterable 接口的其他数据结构 例如数组、对象、Map、Set作为参数进行初始化
let set = new Set([1,2,3,4,4]); // {1,2,3,4}
// 相关API
let set = new Set([1,2,3,4,4]); // {1,2,3,4}
set.add('5'); // {1,2,3,4,5}
set.delete('4'); // {1,2,3,5}
set.size; // 4
set.has('1'); // true
set.clear(); // {}
// 遍历操作
let set = new Set([1,2]); // {1,2}
set.keys() // {1,2}
for (let item of set.keys()) {
console.log(item);
}
1
2
set.values() // {1,2}
for (let item of set.values()) {
console.log(item);
}
1
2
set.entries() // {1=>1,2=>2}
for (let item of set.entries()) {
console.log(item);
}
[1,1]
[2,2]
set.forEach((values,key)=>{console.log(values,key)})
1 1
2 2
// 此处set默认是用set.values()进行遍历
for (let item of set)) {
console.log(item);
}
1
2
Set内部判断两个值是否不同,使用的算法叫做“Same-value-zero equality”,它类似于精确相等运算符(===),主要的区别是向 Set 加入值时认为NaN等于自身,而精确相等运算符认为NaN不等于自身。 即
let set = new Set([5,"5"]); // {5, "5"} 5和"5"不相等
let set2 = new Set([NaN,NaN]); // {NaN} NaN !== NaN 但在Set中是相等的
let set3 = new Set([{},{}]); // {{},{}} {} 不等于 {}
Object.prototype.toString.call(new Set())
"[object Set]"
// 数组去重复
[...new Set([1,2,3,3])]; // [1,2,3]
Array.from(new Set([1,2,3,3])); // [1,2,3]
let a = new Set([1, 2, 3]);
let b = new Set([4, 3, 2]);
// 交集
[...a].filter(item=>b.has(item));// [2,3]
// 并集
[...new Set([...a,...b])];// [1,2,3,4]
// a相对于b的差集
[...a].filter(item=>!b.has(item)); // [1]
WeakSet
与Set类似,成员不重复,但成员只能是对象。
垃圾回收机制不考虑 WeakSet,所以无需担心会造成内存泄漏。
对该对象的引用,因为不确定什么时候会消失,所以不允许遍历。
const a = [[1, 2], [3, 4]];
const ws = new WeakSet(a);
// {[1,2],[3,4]}
// 注意,是a数组的成员成为 WeakSet 的成员,而不是a数组本身。如下会报错。
const b = [3, 4];
const ws = new WeakSet(b);
// Uncaught TypeError: Invalid value used in weak set(…)
// 相关API
ws.add();
ws.has();
ws.delete();
ws.size // undefined
ws.forEach // undefined
Map
在对象中,key只能是字符串,因此ES6增加Map数据结构,key值可以为各种类型的值。
任何具有 Iterator 接口、且每个成员都是一个双元素的数组的数据结构都可以作为Map的参数。
const map = new Map([
['name', '张三'],
['title', 'Author']
]);
map.size // 2
map.set('key','value') // {'name'=>'张三','title'=>'Author','key'=>'value'}
map.has('name') // true
map.get('name') // "张三"
map.delete('name') // {'title'=>'Author','key'=>'value'}
map.clear() // {}
// 注意 ['a'] != ['a']
// 如果 Map 的键是一个对象,Map的键就是跟内存地址绑定的,只要内存地址不一样,就视为两个键。
const map = new Map();
map.set(['a'], 555);
map.get(['a']) // undefined
// 如果 Map 的键是一个简单类型,只要两个值严格相等,Map 将其视为一个键。
// new Map([[NaN,NaN],[NaN,2]]); // {NaN=>2} 会被覆盖 因为被认为是同一个key。
// 链式写法
let map = new Map()
.set(1, 'a')
.set(2, 'b')
.set(3, 'c');
// 遍历
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.entries()
for (let [key, value] of map) {
console.log(key, value);
}
// "F" "no"
// "T" "yes"
WeakMap
与Map类似,但键名只能是对象。
垃圾回收机制不考虑 WeakMap,所以无需担心会造成内存泄漏。
对该对象的引用,因为不确定什么时候会消失,所以不允许遍历。
const wm = new WeakMap();
// size、forEach、clear 方法都不存在
wm.size // undefined
wm.forEach // undefined
wm.clear // undefined
wm.get()
wm.set()
wm.has()
wm.delete()