# 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。