Set集合:是一种数据结构,结构类似于数组,且没有重复的值。主要用于数组去重,字符串去重。
(1)创建集合:new Set()
let set =new Set()
方法 | 含义 |
---|---|
add() | 添加值,返回Set结构本身 |
delete() | 删除值,返回一个boolean表示是否删除成功 |
has() | 判断该值是否存在,并返回一个boolean |
clear() | 清除所有值,没有返回值 |
a、add():向集合中添加元素
let set =new Set()
set.add(1)
set.add(2)
set.add(2)//这个2添加不进去,集合里面不能有重复元素
set.add(3).add(12).add(15)
console.log(set)//会打印出集合信息
console.log(...set)//这个会将各个元素打印出来,不会打印出集合信息
console.log([...set])//会以数组方式显示集合
b、delete():从集合删除元素
set.delete(12)//返回true表示删除成功,false表示删除失败
console.log([...set])
c、has():判断集合中是否存在某个值
console.log(set.has(12))//判断集合是否含有12
console.log(set.has(15))
d、clear():清除集合中的所有元素
let set =new Set()
set.add(1)
set.add(2)
set.add(2)//这个2添加不进去,集合里面不能有重复元素
set.add(3).add(12).add(15)
console.log(set)//会打印出集合信息
console.log(...set)//这个会将各个元素打印出来,不会打印出集合信息
console.log([...set])//会以数组方式显示集合
set.delete(12)//返回true表示删除成功,false表示删除失败
console.log([...set])
console.log(set.has(12))//判断集合是否含有12
console.log(set.has(15))
set.clear()
console.log([...set])
集合的遍历:set集合中的key和value是相同的,所有key()和values()是一样的。
A、获取集合的keys和values进行遍历
let set = new Set()
set.add('西安').add('咸阳').add('宝鸡').add('铜川')
for(let i of set.keys()){//keys()函数的作用:获取set中的所有的键(key),返回的值也是集合
console.log(i)
}
console.log('------------------------------')
for(let t of set.values()){//values()函数的作用:获取set中的所有的值(value),返回值也是集合
console.log(t)
}
// 注意:set中的key和value是相同的,即keys()和values()的返回值是一样的
B、通过forEach循环
let set = new Set()
set.add('西安').add('咸阳').add('宝鸡').add('铜川')
set.forEach(function(key,val){//函数的两个参数的值是相同的
// console.log(`${key}:${value}`)
console.log(key)
})
let arr =[11,22,33,44,55]
let set =new Set(arr)
console.log(set)
let arr =[11,22,33,44,55]
let list=[66,77,22,33]
let A =new Set(arr)
let B =new Set(list)
// 实现A和B的并集
let C=new Set([...A,...B])//将A和B的重复元素33剔除掉
console.log('A集合:',...A)
console.log('B集合:',...B)
console.log('A和B的并集:',...C)
let arr =[11,22,33,44,55]
let list=[66,77,22,33]
let A =new Set(arr)
let B =new Set(list)
// 实现A和B的交集
let D = new Set([...A].filter(function(val){//通过过滤器找到A和B都出现的元素
if(B.has(val)){
return val
}
}))
console.log('A和B的交集:',...D)
WeakSet只能是对象的集合,而不能是任何类型的任意值。
WeakSet集合中对象的引用为弱引用。如果没有其他的对WeakSet中对象的引用,那么这些对象会被当成垃圾回收掉。
这也意味着WeakSet中没有存储当前对象的列表。正因为这样,WeakSet 是不可枚举的。即WeakSet中对对象的引用不会被考虑进垃圾回收机制,即只要没有其他的对象引用该对象,则该对象就会被回收,而不管它在不在 WeakSet。
WeakSet 支持 add,has 和 delete 方法,但不支持 size 和 keys(),并且不可迭代,无法遍历。
a、为weakSet添加对象,查看其返回值:
let jack = { name: "jack" }; //jack是一个对象
let weakSet = new WeakSet();
weakSet.add(jack); //为weakSet添加一个对象
console.log(weakSet.has(jack)); //判断weakSet是否含有jack,并输出返回值
得到结果为:true
b、为WeakSet添加除了对象之外的内容,查看其结果:
let jack = { name: "jack" }; //jack是一个对象
let weakSet = new WeakSet();
weakSet.add(1); //为weakSet添加除对象之外的值
程序会报错:TypeError: Invalid value used in weak set,因为WeakSet中只能存放对象。
WeakSet 的应用场景/好处:用于存储DOM节点,而不用担心这些节点从文档移除时会引发内存泄露。
在ES5中没有Map:但是有object对象(采用hash结构:key=value),键(key)的数据类型只能是字符串。
A、属性:size表示集合中的元素个数
B、常用方法:
常用方法 | 说明 |
---|---|
set() | 添加数据 |
get() | 获取数据 |
has() | 判断key是否存在 |
delete() | 删除key |
clear() | 清除所有的key |
☀️举个例子
let map = new Map()//创建Map
map.set('id',1001) //set(key,value)
map.set('name','刘备')
map.set('age',25)
console.log(map.size)
let n = map.get('name')//get(key)
console.log(n)
console.log(map.has('age'))//has(key)
map.delete('id')
console.log(map.has('id'))//键不存在,对应的值也就不见了
map.clear()
console.log(map)
注意:Map的遍历顺序就是插入顺序
方法 | 含义 |
---|---|
keys() | 获取Map的所有key |
values() | 获取Map的所有值 |
entries() | 获取Map所有成员 |
forEach() | 遍历Map的所有成员 |
//创建一个map集合,传入一个二维数组
const map = new Map([
["F", "no"],
["T", "yes"]
])
console.log(map);
输出结果为:Map(2) { ‘F’ => ‘no’, ‘T’ => ‘yes’ }
a、keys():返回map中的所有的键key
☀️举个例子
let map = new Map()//创建Map
map.set('id',1001) //set(key,value)
map.set('name','刘备')
map.set('age',25)
map.set('address','西安')
for(let key of map.keys()){
// console.log(key)//这个只能打印出来键不能打印出来值
console.log(`${key}:${map.get(key)}`)//将键值对打印出来
}
b、values():返回map中的所有值value
☀️举个例子
let map = new Map()//创建Map
map.set('id',1001) //set(key,value)
map.set('name','刘备')
map.set('age',25)
map.set('address','西安')
for(let val of map.values()){
console.log(val)//这个只能打印出来值不能打印出来键
}
c、entries():返回map所有的map成员
☀️举个例子
let map = new Map()//创建Map
map.set('id',1001) //set(key,value)
map.set('name','刘备')
map.set('age',25)
map.set('address','西安')
for(let kv of map.entries()){
console.log(kv)
}
d、forEach:对map的每个元素执行一次提供的函数
let map = new Map()//创建Map
map.set('id',1001) //set(key,value)
map.set('name','刘备')
map.set('age',25)
map.set('address','西安')
map.forEach(function(key,val){
console.log(`${key}:${val}`)
})
Map结构转为数组结构,比较快速的方法是使用扩展运算符(…)。
//创建一个map集合
const map = new Map([
[1, "one"],
[2, "two"],
[3, "three"]
])
//将map的键转化为一个数组
console.log(...map.keys()); //1 2 3
//将map的值转化成一个数组
console.log(...map.values()); //one two three
//将map对象转化成一个数组
console.log(...map.entries()); //[ 1, 'one' ] [ 2, 'two' ] [ 3, 'three' ]
//将map转化成一个数组
console.log(...map); //[ 1, 'one' ] [ 2, 'two' ] [ 3, 'three' ]
let map = new Map()//创建Map
map.set('id',1001) //set(key,value)
map.set('name','刘备')
map.set('age',25)
map.set('address','西安')
// 将key转化为数组
let k = [...map.keys()]
console.log(k) //输出:[ 'id', 'name', 'age', 'address' ]
// 将value转化为数组
let v=[...map.values()]
console.log(v) //输出:[ 1001, '刘备', 25, '西安' ]
// 将key-value转换为数组
let obj = [...map.entries()]
console.log(obj)
//输出:二维数组4行2列:
// [ 'id', 1001 ],
// [ 'name', '刘备' ],
// [ 'age', 25 ],
// [ 'address', '西安' ]
let map = new Map()
map.set('101',15)
map.set('102',5)
map.set('103',150)
map.set('104',28)
map.set('105',19)
map.set('106',30)
console.log(map)
// 将map中value是偶数的键值对(key-value)过滤出来,存入一个新的map中
let map1 = new Map([...map].filter(function([key,val]){
if(val%2==0){
return [key,val]
}
}))
console.log(map1)
const map = new Map([[1, 'one'], [2, 'two'], [3, 'three']]);
map.forEach((value, key, map) => {
console.log(value, key, map);
})
输出结果为:
one 1 Map(3) { 1 => ‘one’, 2 => ‘two’, 3 => ‘three’ }
two 2 Map(3) { 1 => ‘one’, 2 => ‘two’, 3 => ‘three’ }
three 3 Map(3) { 1 => ‘one’, 2 => ‘two’, 3 => ‘three’ }
WeakMap是弱引用Map集合,也用于存储对象的弱引用。WeakMap集合中的键名必须是一个对象,如果使用非对象键名会报错。
集合中保存的是这些对象的弱引用,如果在弱引用之外不存在其他的强引用,引擎的垃圾回收机制会自动回收这个对象,同时也会移除WeakMap集合中的键值对。但是只有集合的键名遵从这个规则,键名对应的值如果是一个对象,则保存的是对象的强引用,不会触发垃圾回收机制。
1、使用WeakMap集合
ES6中的WeakMap类型是一种存储着许多键值对的无序列表,列表的键名必须是非null类型的对象,键名对应的值则可以是任意类型。
WeakMap的接口与Map非常相似,通过set()方法添加数据,通过get()方法获取数据。
let map = new WeakMap();
const o1 = {}; //o1是一个空对象
const o2 = function () { }; //o2是一个空函数
map.set(o1, o2); //给map添加数据,键和值可以是任意对象,甚至是另一个WeakMap对象
map.set(o2, "张三"); //为map添加数据
console.log(map.get(o1)); //[Function: o2]
console.log(map.get(o2)); //张三
WeakMap集合不支持size属性,从而无法验证集合是否为空。
2、WeakMap集合支持的方法
方法 | 含义 |
---|---|
has() | 检测给定的键在集合中是否存在 |
delete() | 移除指定的键值对 |
a、has()使用示例:
let map = new WeakMap();
const o1 = {}; //o1是一个空对象
const o2 = function () { }; //o2是一个空函数
map.set(o1, o2); //给map添加数据,键和值可以是任意对象,甚至是另一个WeakMap对象
map.set(o2, "张三"); //为map添加数据
console.log(map.has(o1)); //判断map中是否含有o1,true
console.log(map.has(o3)); //判断map中是否含有o3,程序报错,ReferenceError: o3 is not defined
b、delete()使用示例:
let map = new WeakMap();
const o1 = {}; //o1是一个空对象
const o2 = function () { }; //o2是一个空函数
map.set(o1, o2); //给map添加数据,键和值可以是任意对象,甚至是另一个WeakMap对象
map.set(o2, "张三"); //为map添加数据
console.log(map.delete(o1)); //删除map中的o1,删除成功返回true
console.log(map.has(o1)); //判断map中是否含有o1
输出结果为:
true
false
3、WeakMap集合的用途
a、储存DOM元素
<button id="btn">点击</button>
<script>
//获取button元素
let myElement = document.getElementById("btn");
let myWeakmap = new WeakMap();
//为myWeakmap添加数据
myWeakmap.set(myElement, { timesClicked: 0 });
//为按钮添加click事件
myElement.addEventListener("click", function () {
//获取myWeakmap键为myElement的值
let logoData = myWeakmap.get(myElement);
//点击一次加一次1
logoData.timesClicked++;
//输出点击的次数
console.log(logoData.timesClicked);
})
</script>
代码中,myElement是一个DOM节点,每当发生click事件,就更新一下状态。我们将这个状态作为键值放在WeakMap里,对应的键名就是myElement。一旦这个DOM节点删除,该状态就会自动消失,不存在内存泄漏风险
b、注册监听事件的listener对象,就很合适用WeakMap实现。
<button class="element1">按钮1</button>
<button class="element2">按钮2</button>
<script>
//获取元素
let element1 = document.querySelector(".element1");
let element2 = document.querySelector(".element2");
const listener = new WeakMap();
//为listener添加两个数据
listener.set(element1, "handler1");
listener.set(element2, "handler2");
//为element1添加click事件
element1.addEventListener("click", function () {
console.log(listener.get(element1));
})
//为element2添加click事件
element2.addEventListener("click", function () {
console.log(listener.get(element2));
})
</script>
监听函数放在WeakMap里面。一旦 DOM 对象消失,跟它绑定的监听函数也会自动消失。
c、 部署私有属性
我们创建对象的时候,通常写一个构造函数
function Person(name) {
this._name = name;
}
Person.prototype.getName = function () {
return this._name;
}
但这时,创建一个Person 对象的时候,我们可以直接访问name属性
const person = new Person("张三");
console.log(person._name); //张三
我们不想让用户直接访问name属性, 直接使用下面的方法将name包装成私有属性。
let Person = (function () {
let privateData = new WeakMap();
function Person(name) { //定义一个函数,参数为name
privateData.set(this, { name: name }); //为privateData设置数据
}
Person.prototype.getName = function () { //设置getName函数
return privateData.get(this).name; //获得privateData中name键的值的name
}
return Person;
}()); //()()该函数设置之后就调用
const person = new Person("张三");
console.log(person.getName());