Skip to content

Commit 76544a9

Browse files
ArvinHlenchen1112
andauthored
Symbol type (#66)
* feat: draft, symbol translated version * feat: translate Symbol * fix: comments * fix: 他 -> 它 * Apply suggestions from code review Co-Authored-By: Len Chen <[email protected]> * fix: review * fix: review * Update 1-js/04-object-basics/03-symbol/article.md Co-Authored-By: Len Chen <[email protected]>
1 parent e294ee2 commit 76544a9

File tree

1 file changed

+95
-92
lines changed

1 file changed

+95
-92
lines changed
+95-92
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,31 @@
11

2-
# Symbol type
2+
# 符號類型(Symbol Type)
33

4-
By specification, object property keys may be either of string type, or of symbol type. Not numbers, not booleans, only strings or symbols, these two types.
4+
根據規格,物件屬性鍵值只可能是字串類型或符號類型。不是數值類型、不是布林類型,只有字串或符號這兩種類型。
55

6-
Till now we've been using only strings. Now let's see the benefits that symbols can give us.
6+
到目前為止,我們一直只用到字串。現在讓我們來看看 Symbol 能給我們帶來哪些好處。
77

8-
## Symbols
8+
## 符號(Symbol)
99

10-
A "symbol" represents a unique identifier.
10+
一個 "symbol" 代表唯一的識別符號。
1111

12-
A value of this type can be created using `Symbol()`:
12+
可以用 `Symbol()` 來創建此類型的值:
1313

1414
```js
15-
// id is a new symbol
15+
// id 是一個新的 Symbol
1616
let id = Symbol();
1717
```
1818

19-
Upon creation, we can give symbol a description (also called a symbol name), mostly useful for debugging purposes:
19+
創建後,我們可以給 Symbol 一個敘述(也稱為 Symbol 名稱),在進行除錯時大多很有用處:
2020

2121
```js run
22-
// id is a symbol with the description "id"
22+
// id 是一個擁有敘述 "id" 的 Symbol
2323
let id = Symbol("id");
2424
```
2525

26-
Symbols are guaranteed to be unique. Even if we create many symbols with the same description, they are different values. The description is just a label that doesn't affect anything.
26+
Symbol 保證是唯一的。即使我們創建了許多擁有相同敘述的 Symbol,它們的值還是不同的。敘述只是一個標籤,不影響任何東西。
2727

28-
For instance, here are two symbols with the same description -- they are not equal:
28+
舉例來說,這裡有兩個擁有相同敘述的 Symbol -- 它們並不相等:
2929

3030
```js run
3131
let id1 = Symbol("id");
@@ -36,12 +36,12 @@ alert(id1 == id2); // false
3636
*/!*
3737
```
3838

39-
If you are familiar with Ruby or another language that also has some sort of "symbols" -- please don't be misguided. JavaScript symbols are different.
39+
如果你熟悉 Ruby 或是其他也同樣擁有所謂 "Symbol" 的語言 -- 請不要被誤導。 JavaScript 的 Symbol 是不一樣的。
4040

41-
````warn header="Symbols don't auto-convert to a string"
42-
Most values in JavaScript support implicit conversion to a string. For instance, we can `alert` almost any value, and it will work. Symbols are special. They don't auto-convert.
41+
````warn header="Symbol 並不會被自動轉換成字串"
42+
JavaScript 中,大部分的值都支援字串的隱性轉換。例如,我們可以 `alert` 幾乎任何值,且它可以正常運作。Symbol 是特殊的。它們不會自動轉換。
4343
44-
For instance, this `alert` will show an error:
44+
例如,這個 `alert` 會顯示錯誤:
4545
4646
```js run
4747
let id = Symbol("id");
@@ -50,17 +50,18 @@ alert(id); // TypeError: Cannot convert a Symbol value to a string
5050
*/!*
5151
```
5252
53-
That's a "language guard" against messing up, because strings and symbols are fundamentally different and should not accidentally convert one into another.
53+
這是一種防止混亂的 "語言防範(language guard)",因為字串與 Symbol 有本質上的不同,不應該意外地將它們互相轉換。
54+
55+
如果我們真的想要顯示一個Symbol,我們需要在它上面明確地呼叫 `.toString()`,像這樣:
5456
55-
If we really want to show a symbol, we need to explicitly call `.toString()` on it, like here:
5657
```js run
5758
let id = Symbol("id");
5859
*!*
59-
alert(id.toString()); // Symbol(id), now it works
60+
alert(id.toString()); // Symbol(id), 現在它可以正常運作了
6061
*/!*
6162
```
6263
63-
Or get `symbol.description` property to show the description only:
64+
或是取得 `symbol.description` 屬性來單純顯示敘述:
6465
```js run
6566
let id = Symbol("id");
6667
*!*
@@ -70,33 +71,33 @@ alert(id.description); // id
7071
7172
````
7273

73-
## "Hidden" properties
74+
## "隱藏(Hidden)" 屬性
7475

75-
Symbols allow us to create "hidden" properties of an object, that no other part of code can accidentally access or overwrite.
76+
Symbol 允許我們創建物件的 "隱藏" 屬性,其他部分的程式碼都無法意外存取到或是覆寫它。
7677

77-
For instance, if we're working with `user` objects, that belong to a third-party code. We'd like to add identifiers to them.
78+
舉例來說,如果我們正在操作屬於第三方程式碼的 `user` 物件們。我們想要增加識別符到它們上。
7879

79-
Let's use a symbol key for it:
80+
讓我們用一個 Symbol 的鍵值來處理:
8081

8182
```js run
82-
let user = { // belongs to another code
83+
let user = { // 屬於另一份程式碼
8384
name: "John"
8485
};
8586

8687
let id = Symbol("id");
8788

8889
user[id] = 1;
8990

90-
alert( user[id] ); // we can access the data using the symbol as the key
91+
alert( user[id] ); // 我們可以用 Symbol 當作鍵值來存取資料
9192
```
9293

93-
What's the benefit of using `Symbol("id")` over a string `"id"`?
94+
比起用字串 `"id"`,用 `Symbol("id")` 我們可以獲得什麼好處?
9495

95-
As `user` objects belongs to another code, and that code also works with them, we shouldn't just add any fields to it. That's unsafe. But a symbol cannot be accessed accidentally, the third-party code probably won't even see it, so it's probably all right to do.
96+
`user` 物件屬於其他程式碼,且那些程式碼同樣會操作它時,我們不應該增加任何欄位到物件上。這樣不安全。但 Symbol 是沒辦法被意外存取的,第三方的程式碼甚至可能不會看到它,所以這麼做沒問題。
9697

97-
Also, imagine that another script wants to have its own identifier inside `user`, for its own purposes. That may be another JavaScript library, so that the scripts are completely unaware of each other.
98+
此外,想像一下此時有另一個腳本想要在 `user` 內放入它們自己的識別符號,用於它們自己的目的。那可能是另一個 JavaScript 套件,所以腳本之間完全不會意識到對方的存在。
9899

99-
Then that script can create its own `Symbol("id")`, like this:
100+
然後該腳本可以創建自己的 `Symbol("id")`,像這樣:
100101

101102
```js
102103
// ...
@@ -105,45 +106,46 @@ let id = Symbol("id");
105106
user[id] = "Their id value";
106107
```
107108

108-
There will be no conflict between our and their identifiers, because symbols are always different, even if they have the same name.
109+
這不會造成我們與其他腳本之間的識別符有任何衝突,因為 Symbol 永遠是不同的,即使他們有相同的名稱。
109110

110-
...But if we used a string `"id"` instead of a symbol for the same purpose, then there *would* be a conflict:
111+
...但如果我們用字串 `"id"` 而非 Symbol,那麼 *就會* 發生衝突:
111112

112113
```js run
113114
let user = { name: "John" };
114115

115-
// Our script uses "id" property
116+
// 我們的腳本使用 "id" 屬性
116117
user.id = "Our id value";
117118

118-
// ...Another script also wants "id" for its purposes...
119+
// ...另一個腳本也想使用 "id"...
119120

120121
user.id = "Their id value"
121-
// Boom! overwritten by another script!
122+
// 碰!被另一個腳本給覆寫了!
122123
```
123124

124-
### Symbols in a literal
125+
### 字面值中的符號
125126

126-
If we want to use a symbol in an object literal `{...}`, we need square brackets around it.
127+
如果我們想要在物件字面值 `{...}` 中使用 Symbol,我們需要方括號包圍它。
127128

128-
Like this:
129+
像這樣:
129130

130131
```js
131132
let id = Symbol("id");
132133

133134
let user = {
134135
name: "John",
135136
*!*
136-
[id]: 123 // not "id: 123"
137+
[id]: 123 // 不是 "id: 123"
137138
*/!*
138139
};
139140
```
140-
That's because we need the value from the variable `id` as the key, not the string "id".
141141

142-
### Symbols are skipped by for..in
142+
這是因為我們需要變數 `id` 的值當作鍵值,而非字串 "id"。
143+
144+
### 符號在 for..in 中被跳過
143145

144-
Symbolic properties do not participate in `for..in` loop.
146+
Symbol 類型的屬性並不參與 `for..in` 迴圈。
145147

146-
For instance:
148+
例如:
147149

148150
```js run
149151
let id = Symbol("id");
@@ -154,16 +156,17 @@ let user = {
154156
};
155157

156158
*!*
157-
for (let key in user) alert(key); // name, age (no symbols)
159+
for (let key in user) alert(key); // name, age(沒有 Symbol)
158160
*/!*
159161

160-
// the direct access by the symbol works
162+
// 直接存取 Symbol 是沒問題的
161163
alert( "Direct: " + user[id] );
162164
```
163165

164-
`Object.keys(user)` also ignores them. That's a part of the general "hiding symbolic properties" principle. If another script or a library loops over our object, it won't unexpectedly access a symbolic property.
166+
`Object.keys(user)` 也會忽略它們。那是一般 Symbol 中 "隱藏屬性" 原則的一部分。如果另一個腳本或是一個套件在我們的物件上循環,它不會不小心存取到 Symbol 類型的屬性。
167+
168+
相反地,[Object.assign](mdn:js/Object/assign) 同時複製字串與 Symbol 屬性:
165169

166-
In contrast, [Object.assign](mdn:js/Object/assign) copies both string and symbol properties:
167170

168171
```js run
169172
let id = Symbol("id");
@@ -176,118 +179,118 @@ let clone = Object.assign({}, user);
176179
alert( clone[id] ); // 123
177180
```
178181

179-
There's no paradox here. That's by design. The idea is that when we clone an object or merge objects, we usually want *all* properties to be copied (including symbols like `id`).
182+
這裡沒有矛盾,就是這樣設計的。想法是當我們複製一個物件,或是合併多個物件時,我們通常想要 *所有* 屬性都被複製(包含像 `id` 這樣的 Symbol )。
180183

181-
````smart header="Property keys of other types are coerced to strings"
182-
We can only use strings or symbols as keys in objects. Other types are converted to strings.
184+
````smart header="其他類別的屬性鍵值會被強行轉換成字串"
185+
在物件中,我們只能使用字串或 Symbol 當作鍵值。其他類型都會被轉成字串。
183186
184-
For instance, a number `0` becomes a string `"0"` when used as a property key:
187+
舉例來說,當一個數值 `0` 被用來當作屬性健值時,它會變成一個字串 `"0"`
185188
186189
```js run
187190
let obj = {
188-
0: "test" // same as "0": "test"
191+
0: "test" // "0": "test" 一樣
189192
};
190193
191-
// both alerts access the same property (the number 0 is converted to string "0")
194+
// 兩個 alerts 都存取到同樣的屬性(數值 0 被轉換成字串 "0"
192195
alert( obj["0"] ); // test
193-
alert( obj[0] ); // test (same property)
196+
alert( obj[0] ); // test (同樣的屬性)
194197
```
195198
````
196199

197-
## Global symbols
200+
## 全局符號
198201

199-
As we've seen, usually all symbols are different, even if they have the same name. But sometimes we want same-named symbols to be same entities. For instance, different parts of our application want to access symbol `"id"` meaning exactly the same property.
202+
正如我們所見,通常所有的 Symbol 都是不同的,即使它們擁有相同的名稱。但是有時候我們想要擁有相同名稱的 Symbol 被當作相同的物體。例如,我們應用程式中的不同部分想用Symbol `"id"` 存取到完全相同的屬性。
200203

201-
To achieve that, there exists a *global symbol registry*. We can create symbols in it and access them later, and it guarantees that repeated accesses by the same name return exactly the same symbol.
204+
為此,存在一個 *全域 Symbol 註冊表(global symbol registry*。我們可以在其中創建 Symbol 並在稍後存取它們,而這確保我們每次存取相同名稱都會回傳相同的 Symbol。。
202205

203-
In order to read (create if absent) a symbol from the registry, use `Symbol.for(key)`.
206+
為了從註冊表中讀取(如果不存在就創建)Symbol,請使用 `Symbol.for(key)`
204207

205-
That call checks the global registry, and if there's a symbol described as `key`, then returns it, otherwise creates a new symbol `Symbol(key)` and stores it in the registry by the given `key`.
208+
該呼叫會檢查全域註冊表,若有個描述為 `key` 的 Symbol 存在,則回傳該 Symbol,否則就以 `Symbol(key)` 創建新的 Symbol,並將其以 `key` 儲存到註冊表中。
206209

207-
For instance:
210+
舉個例子:
208211

209212
```js run
210-
// read from the global registry
211-
let id = Symbol.for("id"); // if the symbol did not exist, it is created
213+
// 從全域註冊表中讀取
214+
let id = Symbol.for("id"); // 如果該 Symbol 不存在,就創建它
212215

213-
// read it again (maybe from another part of the code)
216+
// 再次讀取它(或許從程式碼的另一個部分)
214217
let idAgain = Symbol.for("id");
215218

216-
// the same symbol
219+
// 同樣的 Symbol
217220
alert( id === idAgain ); // true
218221
```
219222

220-
Symbols inside the registry are called *global symbols*. If we want an application-wide symbol, accessible everywhere in the code -- that's what they are for.
223+
註冊表內的 Symbols 稱為 *全域 Symbol*。如果我們想要一個應用程序範圍內的 Symbol,可以在程式碼中隨處存取 -- 這就是它們的用途。
221224

222-
```smart header="That sounds like Ruby"
223-
In some programming languages, like Ruby, there's a single symbol per name.
225+
```smart header="這聽起來像是 Ruby"
226+
在某些程式語言中,像是 Ruby,每個名稱都只有單一個 symbol
224227
225-
In JavaScript, as we can see, that's right for global symbols.
228+
JavaScript 中,如我們所見,只有全域 Symbol 才是如此。
226229
```
227230

228231
### Symbol.keyFor
229232

230-
For global symbols, not only `Symbol.for(key)` returns a symbol by name, but there's a reverse call: `Symbol.keyFor(sym)`, that does the reverse: returns a name by a global symbol.
233+
對於全域 Symbol,不止有 `Symbol.for(key)` 可以根據某個名稱回傳其 Symbol,還有個反向呼叫,`Symbol.keyFor(sym)` 做反過來的事:根據一個全域 Symbol 回傳其名稱。
231234

232-
For instance:
235+
例如:
233236

234237
```js run
235-
// get symbol by name
238+
// 根據名稱取得 Symbol
236239
let sym = Symbol.for("name");
237240
let sym2 = Symbol.for("id");
238241

239-
// get name by symbol
242+
// 根據 Symbol 取得名稱
240243
alert( Symbol.keyFor(sym) ); // name
241244
alert( Symbol.keyFor(sym2) ); // id
242245
```
243246

244-
The `Symbol.keyFor` internally uses the global symbol registry to look up the key for the symbol. So it doesn't work for non-global symbols. If the symbol is not global, it won't be able to find it and return `undefined`.
247+
`Symbol.keyFor` 在內部使用全域 Symbol 註冊表來查詢 Symbol 的鍵值。所以它並不適用於非全域的 Symbol。如果某個 Symbol 不是全域的,此方法將無法找到它,並會回傳 `undefined`
245248

246-
That said, any symbols have `description` property.
249+
是說,任何 Symbol 都有 `description` 屬性。
247250

248-
For instance:
251+
例如:
249252

250253
```js run
251254
let globalSymbol = Symbol.for("name");
252255
let localSymbol = Symbol("name");
253256

254-
alert( Symbol.keyFor(globalSymbol) ); // name, global symbol
255-
alert( Symbol.keyFor(localSymbol) ); // undefined, not global
257+
alert( Symbol.keyFor(globalSymbol) ); // name, 全局 symbol
258+
alert( Symbol.keyFor(localSymbol) ); // undefined, 非全域
256259

257260
alert( localSymbol.description ); // name
258261
```
259262

260-
## System symbols
263+
## 系統符號
261264

262-
There exist many "system" symbols that JavaScript uses internally, and we can use them to fine-tune various aspects of our objects.
265+
JavaScript 內部存在許多 "系統" Symbol,我們可以使用它們來微調物件的各種方面。
263266

264-
They are listed in the specification in the [Well-known symbols](https://tc39.github.io/ecma262/#sec-well-known-symbols) table:
267+
它們列在規格中的 [Well-known symbols](https://tc39.github.io/ecma262/#sec-well-known-symbols) 表格內:
265268

266269
- `Symbol.hasInstance`
267270
- `Symbol.isConcatSpreadable`
268271
- `Symbol.iterator`
269272
- `Symbol.toPrimitive`
270-
- ...and so on.
273+
- ...等等。
271274

272-
For instance, `Symbol.toPrimitive` allows us to describe object to primitive conversion. We'll see its use very soon.
275+
例如,`Symbol.toPrimitive` 允許我們將物件描述為原生值轉換。我們很快就會看到怎麼使用它。
273276

274-
Other symbols will also become familiar when we study the corresponding language features.
277+
當我們研讀相應的語言特性時,也將會更熟悉其他 Symbol。
275278

276-
## Summary
279+
## 總結
277280

278-
`Symbol` is a primitive type for unique identifiers.
281+
`Symbol` 是用於標示唯一識別符號的原生類別。
279282

280-
Symbols are created with `Symbol()` call with an optional description (name).
283+
Symbol 使用 `Symbol()` 與一個可選的敘述(名稱)作為參數來創建。
281284

282-
Symbols are always different values, even if they have the same name. If we want same-named symbols to be equal, then we should use the global registry: `Symbol.for(key)` returns (creates if needed) a global symbol with `key` as the name. Multiple calls of `Symbol.for` with the same `key` return exactly the same symbol.
285+
Symbol 永遠是不同的值,即使它們擁有相同的名稱。如果我們想要同名的 Symbol 也相等,那我們應該使用全域註冊表:`Symbol.for(key)` 回傳(如果需要的話創建)一個以 `key` 作為名稱的全域 Symbol。以相同的 `key` `Symbol.for` 多次進行呼叫,都會回傳完全相同的 Symbol。
283286

284-
Symbols have two main use cases:
287+
Symbol 有兩個主要使用場景:
285288

286-
1. "Hidden" object properties.
287-
If we want to add a property into an object that "belongs" to another script or a library, we can create a symbol and use it as a property key. A symbolic property does not appear in `for..in`, so it won't be accidentally processed together with other properties. Also it won't be accessed directly, because another script does not have our symbol. So the property will be protected from accidental use or overwrite.
289+
1. "隱藏" 物件屬性。
290+
如果我們想要增加一個屬性到 "屬於" 其他腳本或是套件的物件之中,我們可以創建一個 Symbol 並用它當作屬性的鍵值。Symbol 屬性不會出現在 `for..in` 中,所以他不會不小心被其他屬性一起處理。此外它也不能被直接存取,因為其他腳本不擁有我們的 Symbol。所以該屬性將會被保護,以防意外被存取或覆寫。
288291

289-
So we can "covertly" hide something into objects that we need, but others should not see, using symbolic properties.
292+
所以我們可以使用 Symbol 屬性, "秘密地" 將一些我們需要,但其他人不需要的東西藏進物件中。
290293

291-
2. There are many system symbols used by JavaScript which are accessible as `Symbol.*`. We can use them to alter some built-in behaviors. For instance, later in the tutorial we'll use `Symbol.iterator` for [iterables](info:iterable), `Symbol.toPrimitive` to setup [object-to-primitive conversion](info:object-toprimitive) and so on.
294+
2. JavaScript 內部使用了許多系統 Symbol,以類似 `Symbol.*` 的形式被存取。我們可以使用它們來更改一些內建的行為。舉例來說,在之後的教程我們將會在 [迭代(iterables](info:iterable) 中使用 `Symbol.iterator`,設定 [物件轉換原生值(object-to-primitive conversion](info:object-toprimitive) 時使用 `Symbol.toPrimitive`,等等。
292295

293-
Technically, symbols are not 100% hidden. There is a built-in method [Object.getOwnPropertySymbols(obj)](mdn:js/Object/getOwnPropertySymbols) that allows us to get all symbols. Also there is a method named [Reflect.ownKeys(obj)](mdn:js/Reflect/ownKeys) that returns *all* keys of an object including symbolic ones. So they are not really hidden. But most libraries, built-in functions and syntax constructs don't use these methods.
296+
從技術上來說,Symbol 並非 100% 隱藏。有一個內建方法 [Object.getOwnPropertySymbols(obj)](mdn:js/Object/getOwnPropertySymbols) 允許我們取得所有的 Symbol。另外,還有個方法叫做 [Reflect.ownKeys(obj)](mdn:js/Reflect/ownKeys) 會回傳物件中的 *所有* 鍵值,包含 Symbol。所以它們並非真的被隱藏。但大多套件、內建函式和語法結構都不會使用這些方法。

0 commit comments

Comments
 (0)