Set
对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。
Set中的元素只会出现一次,即 Set 中的元素是唯一的。
NaN
和undefined
都可以被存储在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
对象是一些对象值的集合, 并且其中的每个对象值都只能出现一次。
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
更适合(和执行)跟踪对象引用,尤其是在涉及大量对象时。