# Set

Set 对象允许存储任何类型的唯一值,无论是原始值或者是对象引用。

Set和Array 的区别是Set不允许内部有重复的值,如果有只显示一个,相当于去重。虽然Set很像数组,但是他不是数组。

let setArr = new Set(['jspang','技术胖','web','jspang']);
console.log(setArr);//Set {"jspang", "技术胖", "web"}
const s = new Set(["val1", "val2", "val3"]);

console.log(s.values === s[Symbol.iterator]);  // true
console.log(s.keys === s[Symbol.iterator]);    // true

for (let value of s.values()) {
  console.log(value);
}
// val1
// val2
// val3

for (let value of s.keys()) {
  console.log(value);
}
// val1
// val2
// val3

for (let value of s.entries()) {
  console.log(value);
}
// ['val1', 'val1']
// ['val2', 'val2']
// ['val3', 'val3']

for (let value of s[Symbol.iterator]()) {
  console.log(value);
}
// val1
// val2
// val3 

Set实例可以提供一个迭代器,可以通过values()方法及其别名方法keys(),【或者Symbol.iterator属性,它引用values()】取得这个迭代器;entries可以获取数组。

# add

let mySet = new Set();
 
mySet.add(1); // Set(1) {1}
mySet.add(5); // Set(2) {1, 5}
mySet.add(5); // Set(2) {1, 5} 这里体现了值的唯一性
mySet.add("some text"); 
// Set(3) {1, 5, "some text"} 这里体现了类型的多样性
var o = {a: 1, b: 2}; 
mySet.add(o);
mySet.add({a: 1, b: 2}); 
// Set(5) {1, 5, "some text", {…}, {…}} 
// 这里体现了对象之间引用不同不恒等,即使值相同,Set 也能存储

# delete

删除

let setArr = new Set(['jspang','技术胖','web','jspang']);
console.log(setArr);//Set {"jspang", "技术胖", "web"}
 
setArr.add('前端职场');
console.log(setArr); //Set {"jspang", "技术胖", "web", "前端职场"}
 
setArr.delete('技术胖');
console.log(setArr); //Set {"jspang", "前端职场", "web"}

# has

用has进行值的查找,返回的是true或者false。

let setArr = new Set(['jspang','技术胖','web','jspang']);
console.log(setArr);//Set {"jspang", "技术胖", "web"}
 
console.log(setArr.has('jspang'));//true

# clear

清空

let setArr = new Set(['jspang','技术胖','web','jspang']);
console.log(setArr);//Set {"jspang", "技术胖", "web"}
setArr.clear();
 
console.log(setArr);//{}

# for…of…循环

let setArr = new Set(['jspang','技术胖','web','jspang']);
for (let item of setArr){
    console.log(item);
}

# 类型转化

// Array 转 Set
var mySet = new Set(["value1", "value2", "value3"]);
// 用...操作符,将 Set 转 Array
var myArray = [...mySet];
//String
// String 转 Set
var mySet = new Set('hello');  // Set(4) {"h", "e", "l", "o"}
// 注:Set 中 toString 方法是不能将 Set 转换成 String

# 修改基本类型不影响set

let set  = new Set(['val'])
for(let value of set.values()){
	value ='newval'
	console.log(value)//newval
	console.log(set)//Set(1) {'val'}
}

# set的应用

# 数组去重

var mySet = new Set([1, 2, 3, 4, 4]);
[...mySet]; // [1, 2, 3, 4]
# 并集
var a = [1, 2, 3]
var b = [4, 3, 2]
var union = new Set([...a, ...b]); // {1, 2, 3, 4}
# 交集
var a = [1, 2, 3]
var b = new Set([4, 3, 2]);//b如果没有重复的场景,也可以直接用数组下面使用include方法即可
var intersect = new Set(a.filter(x => b.has(x))); // {2, 3}
# 差集

实例:ab两个集合,a是选中的内容,b是后来操作的取消的内容,现在b所有的内容都不允许出现在新的集合中的操作。

// 可直接使用数组和数组的include方法,这里只是为了演示
var a = new Set([1, 2, 3]);
var b = new Set([4, 3, 2]);
var difference = new Set([...a].filter(x => !b.has(x))); // {1}

# size

size属性可以获得Set值的数量。

let setArr = new Set(['jspang','技术胖','web','jspang']);
for (let item of setArr){
    console.log(item);
}
 
console.log(setArr.size);//3

# WeakSet

WeakSet 结构与 Set 类似,也是不重复的值的集合。但是和 Set 有两点不同.

WeakSet 的成员只能是对象,而不能是其他类型的值。

WeakSet 的对象都是弱引用 即WeakSet 中对对象的引用不会被考虑进垃圾回收机制,即只要没有其他的对象引用该对象,则该对象就会被回收,而不管它在不在 WeakSet

const ws = new WeakSet();
const obj = {};
const foo = {};
 
ws.add(window);
ws.add(obj);
 
ws.has(window); // true
ws.has(foo);    // false
 
ws.delete(window);
ws.has(window);    // false

WeakSet 没有size属性和forEach方法,没有办法遍历它的成员;

JavaScript垃圾回收是一种内存管理技术。在这种技术中,不再被引用的对象会被自动删除,而与其相关的资源也会被一同回收。

Map和Set中对象的引用都是强类型化的,并不会允许垃圾回收。这样一来,如果Map和Set中引用了不再需要的大型对象,如已经从DOM树中删除的DOM元素,那么其回收代价是昂贵的。

为了解决这个问题,ES6还引入了另外两种新的数据结构,即称为WeakMap和WeakSet的弱集合。这些集合之所以是“弱的”,是因为它们允许从内存中清除不再需要的被这些集合所引用的对象。

使用场景:储存 DOM 节点,而不用担心这些节点从文档移除时,会引发内存泄漏。

var weakset = new WeakSet(); 
let aObj = {a:'aa'}; 
let bObj = new String('你好'); 
let cObj = new Number(8); 
weakset.add(aObj); 
weakset.add(bObj); 
weakset.add(cObj); 
//—删除—– 
weakset.delete(aObj); 
bObj=null; //把对象删除,weakset中的对象也没了 
console.log(weakset.has(bObj)); //false
console.log(weakset.has(aObj)); //false
console.log(weakset.has(cObj)); //true
console.log(weakset)
//WeakSet {String, Number},虽然显示String存在,但是再点开[[Entries]]只有array(1):[8]
console.log(aObj)//{a:'aa'}
console.log(bObj)//null
console.log(cObj)//Number {8}

注意图片的右上角感叹号,内容为可能与预期值不符合!

var set = new Set(); 
let aObj = {a:'aa'}; 
let bObj = new String('你好'); 
let cObj = new Number(8); 
set.add(aObj); 
set.add(bObj); 
set.add(cObj); 
set.delete(aObj); 
bObj=null; //把对象删除,set中仍然有
console.log(set.has(bObj)); //false bObj是false,但是和它相同的值set仍有
console.log(set.has(aObj)); //false
console.log(set.has(cObj)); //true
console.log(set)
console.log(aObj)//{a:'aa'}
console.log(bObj)//null
console.log(cObj)//Number {8}

for( let i of set){
	console.log(i)
}
//String {"你好"}
//Number {8}

# set相关面试题

const mySet = new Set([{ a: 1 }, { a: 1 }]); 
const result = [...mySet]; 
console.log(result); 
//[{a: 1}, {a: 1}]

尽管 Set 对象确实会删除重复项,但是尽管具有相同的键值对,但我们使用 Set 创建的两个值是对内存中不同对象的引用。这与 {a:1} === {a:1} 为 false 的原因相同。

应该注意的是,如果集合是使用对象变量创建的,例如 obj = {a:1},则 new Set([obj,obj])将只有一个元素,因为数组中的两个元素都引用内存中的同一对象。

const arr = [...new Set([3, 1, 2, 3, 4])]; 
console.log(arr.length, arr[2]); 

Set 对象将强制唯一元素(集合中已经存在的重复元素将被忽略),但不会更改顺序。所得的 arr 数组将为[3,1,2,4],表示 arr.length 为 4 ,而 arr [2] (数组的第三个元素)为 2。

最后更新: 11/19/2022, 10:03:41 AM