-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path5-4.html
176 lines (173 loc) · 6.72 KB
/
5-4.html
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" href="./public/favicon.ico" />
<meta http-equiv="cache-control" content="no-cache" />
<title></title>
<link rel="stylesheet" href=" https://necolas.github.io/normalize.css/8.0.1/normalize.css" />
<link rel="stylesheet" href="./hightlight/default.min.css" />
<link rel="stylesheet" href="./css/main.css" />
<link rel="stylesheet" href="./css/copybutton.css" />
<link rel="stylesheet" href="./css/hightlight.css" />
<script src="./hightlight/hightlight.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.11/clipboard.min.js"></script>
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-BEVZJDBC7Z"></script>
<script src="./js/gtag.js"></script>
</head>
<body>
<header>
<nav>
<h1>
<span id="toggle-menu"></span>
<a href="index.html"></a>
</h1>
</nav>
</header>
<main>
<aside>
<nav></nav>
</aside>
<article>
<h2>Chapter 5 運用 ECMAScript 集合</h2>
<h2>5-4 的弱集合</h2>
<p>
和 Map 與 WeakMap 類似的方法, WeakSet 弱集合是無法進行迭代的簡化版 Set。在 WeakSet
弱集合中的值必須是唯一的物件參考。如果在 WeakSet
相關集合中的值已不再參考至任何物件,它則會受到記憶體垃圾回收機制的管理。
</p>
<p>
你只能夠使用 .set 和 .delete 方法來對 WeakSet 中的資料進行操作,是否具有該筆資料可用 .has
方法傳入一個指定的 value 值。就像是在 Set 集合中操作,這裡並不支援 .get 方法
,因為集合是一維的。
</p>
<p>類似 WeakMap ,我們不被允許將原生資料型態的值,如字串或符號,加入至 WeakSet 中。</p>
<pre><code class="language-js">
const set = new WeakSet()
set.add('a') // TypeError
set.add(Symbol()) // TypeError
</code></pre>
<p>
即使 WeakSet
實體本身無法進行迭代,但將迭代器傳遞至建構子的方式是可允許的。當集合建構完成後,該迭代器會進行迭代以將序列中的每筆資料項加入至集合中,參考下方程式範例。
</p>
<pre><code class="language-js">
const set = new WeakSet([
new Date(),
{},
()=>{},
[1]
])
</code></pre>
<p>
下面範例是 WeakSet 的另一個使用案例,其中的 Car 類別可確保它所提供的方法只能夠被 car
物件呼叫,而每個 car 物件都是 WeakSet 中的資料項。
</p>
<pre><code class="language-js">
const cars = new WeakSet()
class Car {
constructor () {
cars.add(this)
}
fuelUp(){
if(!cars.has(this)){
throw new TypeError('Car#fuelUp called on a non-Car!')
}
}
}
</code></pre>
<p>
再參考一個更好的案例,看看以下的 listOWnProperties
介面,裡頭所指定的物件會被遞迴地進行迭代,以將樹的每項特性輸出。 listOWnProperties
函式也必須面解如何處理環狀參考,以避免陷入無限迥圈中。你會如何實作這樣的 API呢?
</p>
<pre><code class="language-js">
const circle = { cx: 20, cy: 5, r: 15 }
circle.self = circle
listOwnProperties({
circle,
numbers: [1, 5, 7],
sum: (a, b) => a + b
})
// circle.cx: 20
// circle.cy: 5
// circle.r: 15
// circle.self: [circular]
// numbers.0: 1
// numbers.1: 5
// numbers.2: 7
// sum: (a, b) => a + b
</code></pre>
<p>
有一種實作方式是在 WeakSet 中保有一個 seen
參考的串列,這樣我們就不需要擔心非線性的查詢。我們使用 WeakSet 而不是 Set
,原因是實作中並不需要操作到 Set 的特徵功能。
</p>
<pre><code class="language-js">
function listOwnProperties(input){
recurse(input)
function recurse (source, lastPrefix, seen = new WeakSet ()) {
Object.keys (source). forEach(printOrRecurse)
function printOrRecurse(key){
const value = source[key]
const prefix = lastPrefix
?
`${ lastPrefix }.${ key }`: key
const shouldRecur = (
isObject(value) ||
Array.isArray(value)
)
if (shouldRecur){
if (!seen.has(value)) {
seen.add(value)
recurse(value, prefix, seen)
} else {
console.log(`${ prefix }:[circular]`)
}
} else {
console.log(`${ prefix }: ${ value }`)
}
}
}
}
function isObject (value) {
return Object.prototype.toString.call(value) === '[object Object]'
}
</code></pre>
<p>
另一個更常見的案例,就是建構並維持一個 DOM 元件串列。試想一種情況,一個 DOM
函式庫需要以某種方式處理首次互動的 DOM
元件,但是不能夠遺漏任何一個。函式庫可能會想要將子節點加入至 target
元件上,但並沒有一種絕對的方法可辦認這些子節點,而且所使用的方法也不要特別干涉 target
元件。或是這個方法可能可以進行一些具意義的操作,但只會在第一次呼叫時進行。
</p>
<pre><code class="language-js">
const elements = new WeakSet()
function dommy(target) {
if(elements.has(target)) {
return
}
elements.add(target)
// 進行一些操作
}
</code></pre>
<p>
無論是什麼原因,當我們需要保有旗標來標示 DOM 元件的狀態,但不需要明顯地變更 DOM
元件時,WeakSet 便可以派上用場。如果你想要以任意的資料值取代簡單的旗標,那應該也可以使用
WeakSet。當決定是否使用 Map、WeakMap、Set、或 WeakSet
時,你可以思考一些問題。例如:如果你需要保存物件相關的資料,那麼你應該考慮弱集合;如果你只關心某個資料項是否存在,那麼你可能需要
Set:如果你想要建立一個快取,你應該使用 Map。
</p>
<p>
在 ES6
中的集合對經常使用的案例,提供了內建的解決方案,讓使用者不需要再自行實作繁複的程式,例如:Map:或很難正確地運作,如
WeakMap 的運用案例,可將不需要使用的參考於記憶證中清除,以避免記憶體洩漏。
</p>
</article>
</main>
</body>
<script type="module" src="./js/main.js"></script>
</html>