Set
ES6
提供了新的数据结构Set
。它类似于数组,但是成员的值都是唯一的,没有重复的值。
基本用法
Set.prototype.size
:返回Set
实例的成员总数。Set.prototype.add(value)
:添加某个值,返回 Set 结构本身。Set.prototype.delete(value)
:删除某个值,返回一个布尔值,表示删除是否成功。Set.prototype.has(value)
:返回一个布尔值,表示该值是否为Set
的成员。Set.prototype.clear()
:清除所有成员,没有返回值。
const setNum = new Set([1, 2, 3, 1]); // SetNum构造函数初始化
console.log(setNum.size);// 3
setNum.add(4); //向集合中添加不存在的元素
console.log(setNum.has(2));//true
for (const item of setNum) {
console.log(item);
}
// 1 2 3 4
setNum.delete(2);//删除集合中的某个元素
console.log(setNum.has(2));//false
setNum.clear();//清空集合
console.log(setNum.size);//0
使用内置构造函数创建Set。如果不传入任何参数,将创建一个空的Set。上例中由于Set成员的值都是唯一的,最后setNum
中只会存在一个2。如果add(添加)一个2,是没有效果的。
遍历方法
Set
结构的实例有四个遍历方法,可用于遍历成员
Set.prototype.keys()
:返回键名的遍历器。Set.prototype.values()
:返回键值的遍历器。Set.prototype.entries()
:返回键值对的遍历器。Set.prototype.forEach()
:使用回调函数遍历每个成员。
const 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"]
set.forEach((value, key) => {
console.log(key, value);
});
// red,red green,green blue,blue
上面代码中,entries
方法返回返回的遍历器,也就是数组。同时包括键名和键值,每次输出的数组,它的两个成员都相同。forEach
方法的参数就是接收一个回调函数。依次是键名、键值、集合本身(本例中省略了该参数)。还有第二个参数,表示绑定回调函数内部的this
。
遍历应用
去重数组和字符串.
// 去除数组的重复成员
const arr = [3, 5, 2, 2, 5, 5];
const unique = [...new Set(arr)];// [3, 5, 2]
//也可以去除字符串里面的重复字符
const str =[...new Set('ababbc')].join('');// "abc"
结合扩展运算符...
实现两个集合的并集、交集、差集。
const a = new Set([1, 2, 3]);
const b = new Set([4, 3, 2]);
// 并集
const union = new Set([...a, ...b]);
// Set {1, 2, 3, 4}
// 交集
const intersect = new Set([...a].filter(x => b.has(x)));
// set {2, 3}
// (a 相对于 b 的)差集
const difference = new Set([...a].filter(x => !b.has(x)));
// Set {1}
WeakSet
WeakSet
结构与Set
类似,也是不重复的值的集合,但是与Set
有两个区别。首先,WeakSet
的成员只能是对象,而不能是其他类型的值。
const ws = new WeakSet();
ws.add({});
ws.add(1);// TypeError: Invalid value used in weak set
其次,WeakSet
中的对象都是弱引用,即垃圾回收机制不考虑WeakSet
对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于WeakSet
之中。
WeakSet
结构有以下三个方法:
WeakSet.prototype.add(value)
:向WeakSet
实例添加一个新成员。返回WeakSet
结构本身WeakSet.prototype.delete(value)
:清除WeakSet
实例的指定成员。返回一个布尔值,表示删除是否成功。WeakSet.prototype.has(value)
:返回一个布尔值,表示某个值是否在WeakSet
实例之中。
const obj = { name: 'jake' }
const ws = new WeakSet();
ws.add(obj);
console.log(ws.has(obj));//true
console.log(ws.delete(obj));//true
console.log(ws.has(obj));//false
WeakSet
没有size
属性,没有办法遍历它的成员。因为成员都是弱引用,随时可能消失,遍历机制无法保证成员的存在,很可能在遍历结束,成员就取不到了。
Map
JavaScript
的对象,本质上是键值对的集合,但是传统上只能用字符串当作键。
<div id="firstElement"></div>
<div id="secondElement"></div>
<script>
const firstElement = document.getElementById("firstElement");
const secondElement = document.getElementById("secondElement");// 创建两个HTML元素
const map = {};//定义空对象,使用映射存储HTML节点的额外信息
map[firstElement] = { data: "firstElement" };
console.log(map[firstElement].data === "firstElement");//true
map[secondElement] = { data: "secondElement" };
console.log(map[firstElement].data === "firstElement");//false
console.log(map[secondElement].data === "secondElement");//true
</script>
当我们第一次访问map[firstElement].data
时结果是firstElement
,然后给map对象第二次添加数据。在访问map[firstElement].data
发现值变成了secondElement
。因为对象的key必须是字符串,当用HTML元素作为key时,其值被tostring
方法静默装换成为了字符串类型(“[object HTMLDivElement]
”)。 覆盖了第一个元素的值。
Map基本用法
Map.prototype.size
:返回Map
实例的成员总数。Map.prototype.set(key,value)
:set
方法设置键名key
对应键值为value
,返回整个Map
结构,如果key
已经有值,则键值会被更新,否则就新生成该键。Map.prototype.get(key)
:get方法读取key对应的键值,如果找不到key,返回undefined
。Map.prototype.delete(key)
:删除某个值,返回一个布尔值,表示删除是否成功。Map.prototype.has(key)
:返回一个布尔值,表示该值是否为Map
的成员。Map.prototype.clear()
:清除所有成员,没有返回值。
const map = new Map(); // 使用Map构造函数创建map
const ninja1 = { name: "Jake" };
const ninja2 = { name: "David" };
const ninja3 = { name: "Helen" }; // 定义3个ninja对象
map.set(ninja1, { age: 20 });//使用Map的set方法,建立两个ninja对象的映射关系
map.set(ninja2, { age: 30 });
// 使用Map的get方法获取ninja对象
console.log(map.get(ninja1).age === 20); //true
console.log(map.get(ninja2).age === 30); //true
// 验证第三个ninja对象不存在映射关系
console.log(map.get(ninja3) === undefined); //true
// 验证map中只存在前两个对象的映射
console.log(map.size === 2);//true
//使用has方法一验证map中是否存在指定的key
console.log(map.has(ninja1) === true && map.has(ninja2) === true);// true
//使用delete方法从map中删除key
map.delete(ninja1);
console.log(map.has(ninja1) === false && map.size === 1);//true
//使用clear方法完全清空map
map.clear();
console.log(map.size === 0);//true
遍历方法
Set
结构的实例有四个遍历方法,可用于遍历成员
Map.prototype.keys()
:返回键名的遍历器。Map.prototype.values()
:返回键值的遍历器。Map.prototype.entries()
:返回键值对的遍历器。Map.prototype.forEach()
:使用回调函数遍历每个成员。
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"
map.forEach((value, key) => {
console.log(key, value);
});
// "F" "no" "T" "yes"
Map应用
Map和数组转换
//Map转为数组
const myMap1 = new Map()
.set('Jake', 20)
.set({foo: 3}, ['abc']);
console.log([...myMap1]);// [['Jake', 20], [{foo: 3}, ['abc']]]
//数组转为Map
const myMap2 =new Map([
['Jake', 20],
[{foo: 3}, ['abc']]
]);
console.log(myMap2);
// Map {
// "Jake" => 20,
// Object {foo: 3} => ['abc']
// }
Map和对象转换
//Map转为对象
//如果map的键都是字符串,可以无损的转换为对象
const myMap1 = new Map([
['Jake', 20],
['David', 30]
]);
function mapToObj(map) {
const obj = {};
map.forEach((value, key) => {
obj[key] = value;
})
return obj;
}
console.log( mapToObj(myMap1));
//对象转换Map
const obj = {"a":1, "b":2};
const myMap2 = new Map(Object.entries(obj));
WeakMap
WeakMap
结构与Map
结构类似,也是用于生成键值对的集合。首先,WeakMap
只接受对象作为键名,不接受其他类型的值作为键名。
const wm = new WeakMap();
wm.set({},1);
wm.set(1,1);//Invalid value used as weak map key
其次,WeakMap
的键名所指向的对象,不计入垃圾回收机制。键值依然是正常使用。
const wm = new WeakMap();
let key1 = {};
let obj1 = {foo: 1};
let key2 = {foo: 1};
let obj2 = {};
wm.set(key1, obj1);
wm.set(key2, obj2);
obj1 = null;
key2 = null;
wm.get(key1);// {foo: 1}
wm.get(key2);// undefined
WeakMap
的语法:
-
WeakMap.prototype.set(key,value)
:set
方法设置键名key
对应键值为value
,返回整个Map
结构,如果key
已经有值,则键值会被更新,否则就新生成该键。 -
WeakMap.prototype.get(key)
:get方法读取key对应的键值,如果找不到key,返回undefined
。 -
WeakMap.prototype.delete(key)
:删除某个值,返回一个布尔值,表示删除是否成功。 -
WeakMap.prototype.has(key)
:返回一个布尔值,表示某个值是否在WeakSet
实例之中。 -
WeakMap.prototype.delele(key)
:返回一个布尔值,表示某个值是否在WeakMap
实例之中。
<div id="foo"></div>
<div id="fn"></div>
<script>
const wm = new WeakMap();
const foo = document.querySelector('#foo');
const fn = document.querySelector('#fn');
wm.set(foo,1);
wm.set(fn,2);
console.log(wm.get(foo));// 1
console.log(wm.delete(foo));// true
console.log(wm.has(foo));// false
console.log(wm.has(fn));// true
</script>