Set-WeakSet (es6)
数据结构:存放数据的方式
js中Array可以使用下标,Map和Set不能使用下标。但是Array,Map,Set都属于iterable类型。使用iterable内置的forEach方法。
1 Set的基本使用
96.PNG// 1.创建Set结构
const set = new Set();
set.add(10);
set.add(20);
set.add(30);
set.add(40);
set.add(10);
console.log(set);
console.log(Object.prototype.toString.call(set))//[object Set]
//set 结合 --》不允许数据的重复
//Set(4) {10, 20, 30, 40}
// 2.添加对象时特别注意:
set.add({});
set.add({});
console.log(set);
//Set(6) {10, 20, 30, 40, {…}, …}
//两个空对象对应两个不同的内存地址,因此不是重复的数据
const obj = {}
set.add(obj)
set.add(obj)
console.log(set)
//Set(7) {10, 20, 30, 40, {…},{…},{…}}
//这时候obj是重复的,只能往set里面加一个
// 3.对数组去重(去除重复的元素)
const arr = [33, 10, 26, 30, 33, 26]
//const newArr = [];
/* for(let item of arr){
console.log(newArr.indexOf(item));
if(newArr.indexOf(item) == -1){
newArr.push(item);
}
} */
//console.log(newArr);//(4) [33, 10, 26, 30]
//https://www.runoob.com/jsref/jsref-indexof-array.html
const arrSet = new Set(arr);
//可以放一个可迭代的对象作为参数
console.log(arrSet);
//Set(4) {33, 10, 26, 30}
//如果想转换为一个数组的话
//方法1:Array.from将类数组对象或可迭代对象转化为数组。
const newArr = Array.from(arrSet)
console.log(newArr);
//(4) [33, 10, 26, 30]
//方法2:展开语法(构造数组时)
const newArr2 = [...arrSet]
console.log(newArr2); //[object Array]
//(4) [33, 10, 26, 30]
2 Set的常见方法
97.PNGconst set = new Set()
set.add(10)
set.add(20)
set.add(40)
set.add(333)
// 1.size属性 返回Set中元素的个数;
console.log(set.size);//4
// 2.Set的方法
//add
set.add(100);
console.log(set);
//Set(5) {10, 20, 40, 333, 100}
//delete
//把元素传进去
set.delete(40);
console.log(set);
//Set(4) {10, 20, 333, 100}
//has 有没有包含某个元素
console.log(set.has(100)) //true
//clear
//set.clear()
console.log(set);//Set(0) {size: 0}
//3.对Set进行遍历
//forEach(callback, [, thisArg]):通过forEach遍历set;
set.forEach(item =>{
console.log(item);
})
for( const item of set){
console.log(item);
}
1 WeakSet的使用
98.PNG强引用就是一个小孩A牵着一条狗,他们之间通过狗链儿连着
弱引用就是,旁边有个小孩B指着A牵的狗,说:嘿,那有条狗,B指向那条狗,但他们之间没有是指绑在一起的东西
当A放开狗链,狗就会跑掉(被垃圾回收),无论B是不是还指着
但是,当B不再指着那条狗,狗还被A牵着,不会影响它是否跑掉
- 区别1
// 1.区别一: 只能存放对象类型,不能存放基本数据类型
// Uncaught TypeError: Invalid value used in weak set
//weakSet.add(1)
-
区别2
区别二: weakSet对对象是一个弱引用
什么什么叫做弱引用?
(1)原来对象在内存如果不再用,会被GC回收掉
let obj = {
name: "why"
}
obj不会被回收掉,因为obj指这这个对象。
只要时从根对象开始,能找到某个对象,这个对象就不会被回收掉。
{name:“why”}有个内存地址ox100,有个引用指向它,就是obj。通过let或者const创建出来的变量名称,是在VE里面,在ES5以前,VO对应的GO看成时根对象。但是有了VE之后,VE对应的VARIABLE,这个对象可以看成时根对象,这里的obj看成是在VE-》variable里面,es5之前VO里面的GO是根对象,es5之后,VE里面的variable_是根对象。
根对象里面有个obj的属性指着(引用)这堆内存里面0x100地址的这个对象。
垃圾回收期会不定时查看当前有哪些对象没有引用指向它,没有的话,这个对象到时候会被销毁掉。
当前ox100这个地址的对象是不会被GC回收掉的,因为从根对象开始,有个引用指着它.
(2)
let obj = {
name: "why",
friend:{
name : "kobe"
}
}
从根对象有引用指向ox100这个对象,所以ox100这个对象不会被销毁,
在ox100这个对象里面有个引用指向ox200这个对象,所以ox200这个对象也不会被销毁
这种情况,这两个对象都是不会被销毁的。
101.PNG如果让obj.friend = null,这就意味着ox100里面的friend的值已经不是ox200了,叫做null了,对ox200的指向已经不存在了。可以把null理解成内存里面0x0的地方。这个空的地址。ox200就会被回收掉。
如果obj=null,意味着,ve里面的variable_里面的obj指向空地址oxo,ox100这个对象也会被回收掉。
回到最初,obj的指向ox100的这种引用,成为强引用(strong reference).在GC准备回收这个东西的时候,认为obj指向ox100这个线是有效的。
弱引用叫做weak reference,虽然可能有一条引用,比如info也保存的是ox200, 然后我通过某种办法,让指向ox200这个对象的线是弱引用。GC是不会根据弱引用这条线判断的,就算有弱引用,没有强引用,也会被回收掉。
可以通过弱引用使用对象里面的东西,打印里面的东西。
102.PNG(3)可以把对象放到weakSet里面,但是创建出来的实例对对象的引用时弱引用。
但是,set创建出来的实例对象对对象时强引用。
set:内存表现
这里的obj在VE里面。这时候,VE的variable_里面的属性obj指向ox100这个对象,所以ox100这个对象是不会被销毁的。接下来,new了一个新的set对象,set对象也是一个对象,地址时ox200。
然后:set.add(obj), 不是直接把obj对象里面的内容放到set指向的对象里,而是把obj这个对象的地址放到set指向的这个对象里面。这时候,就多了一个引用,就是set指向的这个对象指向ox100. 这时候,这个ox100就相当于有两个被引用,
103.PNG如果这时候让 obj = null, 相当于obj不再指向ox100这个对象,那么ox100这个对象会不会被销毁掉?
是不会被销毁掉的,因为从set出发,也是从根对象出发,(VE的variable_里面的属性set)出发,有对ox100的引用。
<img src="img/104.PNG" alt="alt" style="zoom:50%;" />
因为0x100不会被销毁,所以set对对象的引用时一种强引用。
(4) 如果时weakSet创建出来的对象,
let obj = {
name: "why"
}
const weakSet = new weakSet()
// 建立的是弱引用
weakSet.add(obj)
黄色的地方就变成了弱引用,如果obj=null,对ox100的引用也不存在了,那么GC到时候就会回收ox100这个对象
<img src="img/105.PNG" alt="alt" style="zoom:50%;" />
2 WeakSet的应用
99.PNG// 3.WeakSet的应用场景
const personSet = new WeakSet()
class Person {
constructor() {
personSet.add(this)
}
running() {
if (!personSet.has(this)) {
throw new Error("不能通过非构造方法创建出来的对象调用running方法")
}
console.log("running~", this)
}
}
let p = new Person()
p.running()
p = null
p.running.call({name: "why"})
为什么不能用set
// 3.WeakSet的应用场景
const personSet = new Set()
class Person {
constructor() {
personSet.add(this)
}
running() {
if (!personSet.has(this)) {
throw new Error("不能通过非构造方法创建出来的对象调用running方法")
}
console.log("running~", this)
}
}
let p = new Person()
p.running()
p.running.call({name: "why"})
//p = null
//为什么不能用set呢
//personSet.add(this)
//this(创建出来的p实例)会被强引用,如果有一天p=null,那么p指向的那个对象也不会被销毁
//因为被personSet强引用,
//这个p指向的对象不会被销毁的
//导致===》就算想销毁p也销毁不掉
//只能p=null之后,personSet.delete(p),才能让p指向的对象被回收