天天看点

整理学习——ES6的Set和WeakSetSet([iterable])

文章目录

  • Set([iterable])
    • 属性
      • Set.length
      • get Set[@@species]
      • Set.prototype
    • 实例
      • 属性
        • Set.prototype.constructor
        • Set.prototype.size
      • 方法
        • Set.prototype.add(value)
        • Set.prototype.clear()
        • Set.prototype.delete(value)
        • Set.prototype.entries()
        • Set.prototype.forEach(callbackFn[,thisArg])
        • Set.prototype.has(value)
        • Set.prototype.keys()
      • Set.prototype.values()
      • Set.prototype[@@iterator]()
    • 应用
      • 去除数组的重复成员
      • 实现并集、交集和差集
      • 在遍历操作中修改Set对象
    • WeakSet
      • 与Set的区别
      • 属性
        • WeakSet.length
        • WeakSet.prototype
      • 实例
        • 属性
          • WeakSet.prototype.constructor
        • 方法
          • WeakSet.prototype.add(value)
          • WeakSet.prototype.delete(value)
          • WeakSet.prototype.has(value)
      • 注意
      • 应用

Set([iterable])

本身是一个构造函数,用来生成Set数据结构。它可以存储任何类型的唯一值,无论是原始值或者是对象引用。

  1. Set结构不会添加重复的值。而且Set内部判断两个值是否不同,使用的算法和Object.is(v1,v2)的方法相同,类似于===,但是NaN等于自身。
  2. Set函数可使用iterator结构的对象作为参数来进行初始化
function outputSet(set){
	for(let v of set){
		console.log(v);
	}
}
var s = new Set();
var arr = [1,23,4,5,6,4,3];
arr.map(a => s.add(a));
outputSet(s);
/*Output
1
23
4
5
6
3
*/

var initSet = new Set(arr);
outputSet(initSet);
/*Output
1
23
4
5
6
3
*/
           

利用其不会添加重复值的特点,去除重复值

var arr = [1,2,3,4,2,1,3,5,4,6,NaN,NaN];
arr = [...new Set(arr)];
console.log(arr);
//Output: [1, 2, 3, 4, 5, 6, NaN]
           

属性

Set.length

值为0

get Set[@@species]

构造函数用来创建派生对象

Set.prototype

表示Set构造器的原型,允许先所有Set对象添加新的属性。

实例

以下列代码为例

function outputSet(set){
	for(let v of set){
		console.log(v);
	}
}

var arr = [1,2,4,5,2,5,4,3,5,4];
var expSet = new Set(arr);
           

属性

Set.prototype.constructor

返回实例的构造函数。默认情况下是Set()。

expSet.__proto__.constructor;
//result: ƒ Set() { [native code] }
           

Set.prototype.size

返回Set对象的值的个数

expSet.size
//result: 5
           

方法

Set.prototype.add(value)

在Set对象尾部添加一个元素。返回该Set对象

expSet.add("val");
outputSet(expSet);
/*Output:
1
2
4
5
3
val
*/
           

Set.prototype.clear()

移除Set对象内的所有元素

Set.prototype.delete(value)

移除Set对象中与这个值相等的元素,返回和

Set.prototype.has(value)

相同的结果。

  • 如果Set对象中存在与这个值相等的元素,则返回true;
  • 如果不存在,则返回false。

    在运行之后,因为目标值已被删除,所以再次运行便为false。

expSet.delete("val");
//result: true
outputSet(expSet);
/*Output:
1
2
4
5
3
*/
expSet.delete("val");
//result: false
           

Set.prototype.entries()

返回一个新的迭代器对象,该对象包含Set对象中安插入顺序排列的所有元素的值的[value, value]数组。为了使这个方法和Map对象保持相似,每个值的键和值相等。

var obj = expSet.entries();
console.log(obj);
//Output: SetIterator {1 => 1, 2 => 2, 4 => 4, 5 => 5, 3 => 3}
           

Set.prototype.forEach(callbackFn[,thisArg])

按照顺序,为Set对象中的每一个值调用一次callbackFn。第二个参数是回调函数中的this会是这个参数。

var obj = {
	arg: "arg"
};
var val = "";
expSet.forEach(function(x){
	val += this.arg + x;
}, obj);
console.log(val);
//Output: "arg1arg2arg4arg5arg3";
           

Set.prototype.has(value)

返回一个布尔值,表示该值在Set中存在与否。

Set.prototype.keys()

与values()方法相同,返回一个新的额迭代器对象,该对象包含Set对象中的按插入顺序排列的所有元素的值。

expSet.keys();
//result: SetIterator {1, 2, 4, 5, 3}
           

Set.prototype.values()

返回一个新的迭代器对象,该对象包含Set对象中的按插入顺序排列所有元素的值。

expSet.values()
//result: SetIterator {1, 2, 4, 5, 3}
           

Set.prototype@@iterator

返回一个新的迭代器对象,该对象包含Set对象中的按插入顺序排列的所有元素的值。

应用

去除数组的重复成员

let arr = [1,2,1,2];
let arr2 = [...new Set(arr)];
           

实现并集、交集和差集

var a = new Set( [1,2,3,4] ), 
	b = new Set([4,5,6]);
//并集
let union = new Set([...a, ...b]);
//交集
let intersect = new Set([...a].filter(x => b.has(x)));
//差集
let diff = new Set([ ...[...a].filter(x => !b.has(x)), ...[...b].filter(x => !a.has(x))])
           

在遍历操作中修改Set对象

在遍历过程中,没有直接的方法。但是有以下两种方式。

  1. 利用原Set结构映射出一个新的结构,然后赋值给原来的Set结构
  2. 利用Array.from(Object[, fn]);
let set = new Set([1,2,3]);
set = new Set([...set].map(val => val * 2 ));
set = new Set([1,2,3]);
set = new Set(Array.from(set,val => val *2));
           

WeakSet

与Set的区别

  1. WeakSet的成员只能是对象
  2. WeakSet中的对象都是弱引用,即垃圾回收机制不考虑WeakSet对该对象的引用。即如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存。所以,无法引用WeakSet的成员,不可遍历WeakSet。
var ws = new WeakSet();
ws.add(1);
//result: Uncaught TypeError: Invalid value used in weak set
           

作为构造函数,WeakSet可以接收一个具有iterable接口的对象作为参数,让其自动成为WeakSet实例对象的成员。但是这个参数的成员必须为对象。一旦不是对象,那么,就会向上面代码那样报同样的错误。

var a = [[1,2],{val1: 3}];
var ws = new WeakSet(a);
console.log(ws);
//Output: WeakSet {Array(2), {…}}
           

属性

以以下代码为例

var ws = new WeakSet();
var obj1 = {};
           

WeakSet.length

值为0。实例该属性为undefined

console.log(WeakSet.length, ws.length);
//Output: 0 undefined
           

WeakSet.prototype

对应实例的所有继承属性和继承方法都在该对象上

实例

属性

WeakSet.prototype.constructor

返回构造函数即WeakSet本身。

方法

WeakSet.prototype.add(value)

在该WeakSet对象中添加一个新元素value,这个value必须是一个具有iterator接口的对象。

ws.add(obj1);
console.log(ws);
//Output: WeakSet {{…}}
           
WeakSet.prototype.delete(value)

从该WeakSet对象中删除value这个元素,之后WeakSet.prototype.has(value)方法会返回false

ws.delete(obj1);
console.log(ws);
//Output: WeakSet {}
           
WeakSet.prototype.has(value)

返回一个布尔值,表示给定的值value是否存在于这个WeakSet中。

ws.add(obj1);
ws.has(obj1);
//result: true
ws.delete(obj1);
//result: true
ws.has(obj1);
//result: false
           

注意

  1. WeakSet.prototype.clear() 已废弃,不再使用。
  2. WeakSet的成员不适合引用,因为它随时会消失,WeakSet内部有多少个成员,取决于垃圾回收机制有没有运行。所以规定了WeakSet不可遍历。也不会造成内存溢出的问题。

应用

  1. 存储DOM节点,不用担心节点从文档移除时会引发内存泄露。
  2. 保证构造函数的实例方法,只能在其实例上调用。这里使用WeakSet的好处是,foos对实例的引用,不会被计入内存回收机制,所以删除实例的时候,不用考虑foos,也不会出现内存泄露。
    const foos = new WeakSet();
    class Foo {
    	constructor(){
    		foos.add(this);
    	}
    	method (){
    		if(!foos.has(this)){
    			throw new TypeError('Foo.prototype.method 只能在Foo的实例上调用!');
    		}
    	}
    }
               

参考地址

http://caibaojian.com/es6/set-map.html

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Set

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/WeakSet

https://blog.csdn.net/jiandan1127/article/details/90670241

继续阅读