ES6 Set、WeakSet

Set、WeakSet

Set

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

Set中的元素只会出现一次,即 Set 中的元素是唯一的。

NaNundefined都可以被存储在Set 中, NaN之间被视为相同的值(NaN被认为是相同的,尽管 NaN !== NaN)。

创建一个Set对象:

new Set([iterable])

iterable为可选参数,如果传递一个可迭代对象,它的所有元素将不重复地被添加到新的 Set中。

如果不指定此参数或其值为null,则新的 Set为空。

属性:

size

返回Set对象中元素的个数。

var mySet = new Set();
mySet.add(1);
mySet.add(5);
mySet.add("some text")

mySet.size; // 3

方法:

Set.prototype.add(value)

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

Set.prototype.clear()

移除Set对象内的所有元素。

Set.prototype.delete(value)

移除Set中与这个值相等的元素,返回Set.prototype.has(value)在这个操作前会返回的值(即如果该元素存在,返回true,否则返回false)。Set.prototype.has(value)在此后会返回false

Set.prototype.entries()

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

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

按照插入顺序,为Set对象中的每一个值调用一次callBackFn。如果提供了thisArg参数,回调中的this会是这个参数。

Set.prototype.has(value)

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

Set.prototype.keys()

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

Set.prototype.values()

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

Set.prototype[@@iterator]()

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

Set与Array

let myArray = ["value1", "value2", "value3"];

// 用Set构造器将Array转换为Set
let mySet = new Set(myArray);

mySet.has("value1"); // returns true

// 用...(展开运算符)将Set转换为Array
console.log([...mySet]); // 与myArray完全一致

实现数组去重

const numbers = [2,3,4,4,2,3,3,4,4,5,5,6,6,7,5,32,3,4,5]
console.log([...new Set(numbers)])
// [2, 3, 4, 5, 6, 7, 32]

WeakSet

WeakSet 对象是一些对象值的集合, 并且其中的每个对象值都只能出现一次。

 new WeakSet([iterable]);

如果传入一个可迭代对象作为参数, 则该对象的所有迭代值都会被自动添加进生成的 WeakSet 对象中。null 被认为是 undefined。

WeakSet没有属性,只有三个实例方法。

方法:

add(value)

add() 方法在 WeakSet 对象的最后一个元素后添加新的对象。

ws.add(value);

value必须。 将对象添加进 WeakSet 集合中。

var ws = new WeakSet();

ws.add(window); // 添加 window 对象进 WeakSet 中

ws.has(window); // true

// Weakset 仅取得对象作为参数
ws.add(1);
// 结果为 "TypeError: Invalid value used in weak set" 在 Chrome 浏览器中
// 并且 "TypeError: 1 is not a non-null object" 在 Firefox 浏览器中

delete()

delete() 方法从 WeakSet 对象中移除指定的元素.

ws.delete(value);

value为必须。从 WeakSet 对象中移除的对象。

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

ws.add(window);

ws.delete(obj);    // 返回 false。因为找不到要删除的obj
ws.delete(window); // 返回 true。成功地移除了元素

ws.has(window);    // 返回 false。因为 WeakSet 中已经不存在 window 对象

has()

has() 方法根据 WeakSet 是否存在相应对象返回布尔值。

ws.has(value);

value必须。 测试 WeakSet中是否存在该对象。

如果 WeakSet 对象中存在指定的元素,返回 true;否则返回 false

与Set的区别

它和 Set 对象的区别有两点:

  • Set相比,WeakSet 只能是对象的集合,而不能是任何类型的任意值。
  • WeakSet弱引用:集合中对象的引用为弱引用。 如果没有其他的对WeakSet中对象的引用,那么这些对象会被当成垃圾回收掉。 这也意味着WeakSet中没有存储当前对象的列表。 正因为这样,WeakSet不可枚举的。

检测循环引用

递归调用自身的函数需要一种通过跟踪哪些对象已被处理,来应对循环数据结构的方法。

为此,WeakSet非常适合处理这种情况:

// 对 传入的subject对象 内部存储的所有内容执行回调
function execRecursively(fn, subject, _refs = null){
	if(!_refs)
		_refs = new WeakSet();

	// 避免无限递归
	if(_refs.has(subject))
		return;

	fn(subject);
	if("object" === typeof subject){
		_refs.add(subject);
		for(let key in subject)
			execRecursively(fn, subject[key], _refs);
	}
}

const foo = {
	foo: "Foo",
	bar: {
		bar: "Bar"
	}
};

foo.bar.baz = foo; // 循环引用!
execRecursively(obj => console.log(obj), foo);

在此,在第一次运行时创建WeakSet,并将其与每个后续函数调用一起传递(使用内部参数_refs)。 对象的数量或它们的遍历顺序无关紧要,因此,WeakSet比Set更适合(和执行)跟踪对象引用,尤其是在涉及大量对象时。

上一篇:WeakSet的使用


下一篇:ES6知识