1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
---
title: WeakSet
slug: Web/JavaScript/Reference/Global_Objects/WeakSet
tags:
- WeakSet
translation_of: Web/JavaScript/Reference/Global_Objects/WeakSet
---
<div>{{JSRef}}</div>
<div></div>
<p><strong><code>WeakSet</code></strong> 对象允许你将<em>弱保持对象</em>存储在一个集合中。</p>
<h2 id="语法">语法</h2>
<pre class="syntaxbox"> new WeakSet([iterable]);</pre>
<h3 id="参数">参数</h3>
<dl>
<dt>iterable</dt>
<dd>如果传入一个<a href="/zh-CN/docs/Web/JavaScript/Reference/Statements/for...of">可迭代对象</a>作为参数, 则该对象的所有迭代值都会被自动添加进生成的 <code>WeakSet</code> 对象中。null 被认为是 undefined。</dd>
</dl>
<h2 id="示例">示例</h2>
<h3 id="使用_WeakSet对象">使用 <code>WeakSet</code>对象</h3>
<pre class="brush: js">var ws = new WeakSet();
var foo = {};
var bar = {};
ws.add(foo);
ws.add(bar);
ws.has(foo); // true
ws.has(bar); // true
ws.delete(foo); // 从set中删除 foo 对象
ws.has(foo); // false, foo 对象已经被删除了
ws.has(bar); // true, bar 依然存在</pre>
<p>注意, <code>foo !== bar</code>。 尽管它们是相似的对象,但是它们不是<em><strong>同一个对象。</strong></em>因此,它们都可以被加入到set中。</p>
<h2 id="描述">描述</h2>
<p><code>WeakSet</code> 对象是一些对象值的集合, 并且其中的每个对象值都只能出现一次。在<code>WeakSet</code>的集合中是唯一的</p>
<p>它和 {{jsxref("Set")}} 对象的区别有两点:</p>
<ul>
<li>与<code>Set</code>相比,<code>WeakSet</code> 只能是<strong>对象的集合</strong>,而不能是任何类型的任意值。</li>
<li><code>WeakSet</code>持弱引用:集合中对象的引用为弱引用。 如果没有其他的对<code>WeakSet</code>中对象的引用,那么这些对象会被当成垃圾回收掉。 这也意味着WeakSet中没有存储当前对象的列表。 正因为这样,<code>WeakSet</code> 是不可枚举的。</li>
</ul>
<h3 id="检测循环引用">检测循环引用</h3>
<p>递归调用自身的函数需要一种通过跟踪哪些对象已被处理,来应对循环数据结构的方法。</p>
<p>为此,WeakSet非常适合处理这种情况:</p>
<pre class="brush: js">// 对 传入的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);</pre>
<p>在此,在第一次运行时创建<code>WeakSet</code>,并将其与每个后续函数调用一起传递(使用内部参数_refs)。 对象的数量或它们的遍历顺序无关紧要,因此,WeakSet比{{jsxref("Set")}}更适合(和执行)跟踪对象引用,尤其是在涉及大量对象时。</p>
<h2 id="Properties" name="Properties">属性</h2>
<dl>
<dt><code>WeakSet.length</code></dt>
<dd><code>length</code> 属性的值为 0.</dd>
<dt>{{jsxref("WeakSet.prototype")}}</dt>
<dd>表示<code>WeakSet</code>构造函数的原型。 允许向所有<code>WeakSet</code>对象添加属性。</dd>
</dl>
<h2 id="Boolean_instances" name="Boolean_instances"><code>WeakSet</code> 实例</h2>
<p>所有 <code>WeakSet</code> 实例都继承自 {{jsxref("WeakSet.prototype")}}.</p>
<h3 id="属性">属性</h3>
<p>{{page('zh-CN/Web/JavaScript/Reference/Global_Objects/WeakSet/prototype','Properties')}}</p>
<h3 id="方法">方法</h3>
<p>{{page('zh-CN/Web/JavaScript/Reference/Global_Objects/WeakSet/prototype','Methods')}}</p>
<h2 id="规范">规范</h2>
<table class="standard-table">
<tbody>
<tr>
<td>规范链接</td>
<td>规范状态</td>
<td>备注</td>
</tr>
<tr>
<td>{{SpecName('ES2015', '#sec-weakset-objects', 'WeakSet')}}</td>
<td>{{Spec2('ES2015')}}</td>
<td>Initial definition.</td>
</tr>
<tr>
<td>{{SpecName('ESDraft', '#sec-weakset-objects', 'WeakSet')}}</td>
<td>{{Spec2('ESDraft')}}</td>
<td></td>
</tr>
</tbody>
</table>
<h2 id="浏览器兼容性">浏览器兼容性</h2>
<p>{{Compat("javascript.builtins.WeakSet")}}</p>
<h2 id="相关链接">相关链接</h2>
<ul>
<li>{{jsxref("Map")}}</li>
<li>{{jsxref("Set")}}</li>
<li>{{jsxref("WeakMap")}}</li>
</ul>
|