一、Set
1.基本用法
Set数据类型类似数组,但里面的元素都是唯一的。
var s = new Set();
[2,2,3,4,3,2,2].forEach(x=>s.add(x));
console.log(s); //[2,3,4]
const a = new Set([2,8,4,6,2,2,3]);
console.log(a); //[2,8,4,6,3]
console.log("a的size:" + a.size); //5
console.log("-------------------------");
const c = new Set(document.querySelectorAll('div'));
console.log(c.size); //2,此时body有两个div
- 去除数组重复成员:
var array = [1,2,2,3,3,4,4,4,6];
console.log([...new Set(array)]);//[1,2,3,4,6]
console.log([...new Set(array)].join(''));//12346
- 去除字符串重复字符:
console.log([...new Set("aabbccddee")].join('')); //abcde
在Set内部认为两个NaN是相等的,而两个对象总是不同的。
var d = new Set();
d.add(NaN);
d.add(NaN);
console.log(d.size); //1
d.add({});
d.add({});
console.log(d.size); //3
3.Set 实例的属性和方法
(1)两个属性
Set.prototype.constructor:构造函数,默认就是Set函数。
Set.prototype.size:返回Set实例的成员总数。
var d = new Set();
d.add(NaN);
d.add(NaN);
d.add({});
d.add({});
console.log(d.size); //3
console.log(d.constructor); // ƒ Set() { [native code] }
(2)四个方法
Set.prototype.add(value):添加某个值,返回 Set 结构本身。
Set.prototype.delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
Set.prototype.has(value):返回一个布尔值,表示该值是否为Set的成员。
Set.prototype.clear():清除所有成员,没有返回值。
var e = new Set();
e.add(1);
e.add(2);
e.add(3);
e.delete(1);
console.log(e); //Set(2) {2, 3}
console.log(e.has(1)); //false
console.log(e.has(2)); //true
e.clear();
console.log(e); //Set(0){}
- Array.from() : 可以把Set结构转化为数组
const items = new Set([1, 2, 3, 4, 5]);
const array = Array.from(items);
3.遍历操作
(1)keys(),values(),entries()
Set.prototype.keys():返回键名的遍历器
Set.prototype.values():返回键值的遍历器
Set.prototype.entries():返回键值对的遍历器
Set.prototype.forEach():使用回调函数遍历每个成员
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"]
- Set 结构的实例默认可遍历,它的默认遍历器生成函数就是它的values方法。这意味着,可以省略values方法,直接用for…of循环遍历 Set。
var g = new Set(["red","blue","green"]);
for(let item of g)
{
console.log(item);
}
//red
//blue
//green
(2)forEach()
let set = new Set([1, 4, 9]);
set.forEach((value, key) => console.log(key + ' : ' + value))
// 1 : 1
// 4 : 4
// 9 : 9
(3)遍历的应用
1)去除数组的重复元素
2)数组的并集、交集、差集
二、WeakSet数据结构
WeakSet与set类似,不能有重复的值。与set的区别是,WeakSet的成员之能是对象,不能是其他类型的值。
var a = [[1,2],[3,4]];
const ws = new WeakSet(a);
console.log(ws);
// {[1, 2], [3, 4]}
(1)三个方法:
WeakSet.prototype.add(value):向 WeakSet 实例添加一个新成员。
WeakSet.prototype.delete(value):清除 WeakSet 实例的指定成员。
WeakSet.prototype.has(value):返回一个布尔值,表示某个值是否在 WeakSet 实例之中。
WeakSet没有size属性,所以没办法遍历所有成员。
三、Map
1.含义和基本用法
Map类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。
(1)方法:set(),get(),has(),delete(),
clear():清除所有成员
const m = new Map();
const o = {p:'HelloWorld'};
m.set(o,'abc');
console.log(m.get(o)); //abc
console.log(m.has(o)); //true
m.delete(o);
console.log(m.has(o)); //false
(2)用Map添加成员
console.log(ws);
console.log(ws.size);
console.log(ws.has('name'));
console.log(ws.get("name"));
console.log(ws.has("age"));
console.log(ws.get("age"));
- Map 的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键。
如果 Map 的键是一个简单类型的值(数字、字符串、布尔值),则只要两个值严格相等,Map
将其视为一个键,比如0和-0就是一个键,布尔值true和字符串true则是两个不同的键。另外,undefined和null也是两个不同的键。虽然NaN不严格相等于自身,但
Map 将其视为同一个键。
var m = new Map();
m.set(0,111);
m.set(-0,222);
console.log(m.get(0));
m.set(true,333);
m.set("true",444);
console.log(m.get("true"));
console.log(m.get(true));
m.set(undefined,5);
m.set(null,6);
console.log(m.get(undefined));
console.log(m.get(null));
m.set(NaN,7);
m.set(NaN,8);
console.log(m.get(NaN));
//打印的值
222
444
333
5
6
8
2.遍历方法
Map.prototype.keys():返回键名的遍历器。
Map.prototype.values():返回键值的遍历器。
Map.prototype.entries():返回所有成员的遍历器。
Map.prototype.forEach():遍历 Map 的所有成员。
var m = new Map([
["one",111],
["two",222]
]);
for(let key of m.keys()){
console.log(key);
}
for(let value of m.values()){
console.log(value);
}
for(let [key,value] of m.entries()){
console.log(key,value);
}
//打印结果:
one
two
111
222
one 111
two 222
one 111
two 222
- 把Map结构转化为数组
var m = new Map([
["one",111],
["two",222]
]);
console.log([...m.keys()]);
console.log([...m.values()]);
console.log([...m.entries()]);
console.log([...m]);
m.forEach(function(key,value){
console.log("Key:%s,value:%s",key,value);
})
//打印结果
["one", "two"]
[111, 222]
[["one",111],["two",222]]
[["one",111],["two",222]]
Key:111,value:one
Key:222,value:two
3.与其他数据类型的转换
(1)Map转换为数组:使用扩展运算符(…)。
(2)数组 转为 Map:将数组传入 Map 构造函数,就可以转为 Map
(3)Map 转为对象
function strMapToObj(strMap) {
let obj = Object.create(null);
for (let [k,v] of strMap) {
obj[k] = v;
}
return obj;
}
const myMap = new Map()
.set('yes', true)
.set('no', false);
strMapToObj(myMap)
// { yes: true, no: false }
(4))对象转为 Map:通过Object.entries()。
let obj = {"a":1, "b":2};
let map = new Map(Object.entries(obj));
console.log([...map]);
//打印结果
[["a", 1],["b", 2]]
(5)Map转换为JSON
1)Map 的键名都是字符串,这时可以选择转为对象 JSON。
function strMapToJson(strMap) {
return JSON.stringify(strMapToObj(strMap));
}
let myMap = new Map().set('yes', true).set('no', false);
strMapToJson(myMap)
// '{"yes":true,"no":false}'
2)Map 的键名有非字符串,这时可以选择转为数组 JSON。
function mapToArrayJson(map) {
return JSON.stringify([...map]);
}
let myMap = new Map().set(true, 7).set({foo: 3}, ['abc']);
mapToArrayJson(myMap)
// '[[true,7],[{"foo":3},["abc"]]]'
(6)JSON转为Map
1)所有键名都是字符串
function jsonToStrMap(jsonStr) {
return objToStrMap(JSON.parse(jsonStr));
}
jsonToStrMap('{"yes": true, "no": false}')
// Map {'yes' => true, 'no' => false}
2)整个 JSON 就是一个数组,且每个数组成员本身,又是一个有两个成员的数组。
function jsonToMap(jsonStr) {
return new Map(JSON.parse(jsonStr));
}
jsonToMap('[[true,7],[{"foo":3},["abc"]]]')
// Map {true => 7, Object {foo: 3} => ['abc']}
四、WeakMap
WeakMap结构与Map结构类似,也是用于生成键值对的集合。
1.与Map的区别:
(1)WeakMap只接受对象作为键名(null除外),不接受其他类型的值作为键名。
(2)WeakMap的键名所指向的对象,不计入垃圾回收机制。
2.特点:元素一旦不再需要,WeakMap 里面的键名对象和所对应的键值对会自动消失,不用手动删除引用。
3.WeakMap的用法:
WeakMap 与 Map 在 API 上的区别主要是两个,
(1)没有遍历操作(即没有keys()、values()和entries()方法)
(2)没有size属性。
(3)不可以使用clear()
(4)只能用get(),set(),has(),delete()