1.sysmbol類型
根據(jù)規(guī)范,只有兩種原始類型可以用作對(duì)象屬性鍵:
- 字符串類型
- symbol 類型
“symbol” 值表示唯一的標(biāo)識(shí)符。
可以使用 Symbol() 來(lái)創(chuàng)建這種類型的值:
let id = Symbol();
創(chuàng)建時(shí),我們可以給 symbol 一個(gè)描述(也稱為 symbol 名),這在代碼調(diào)試時(shí)非常有用:
// id 是描述為 "id" 的 symbol let id = Symbol("id");
想顯示一個(gè) symbol,我們需要在它上面調(diào)用 .toString(),如下所示:
let id = Symbol("id");
alert(id.toString()); // Symbol(id),現(xiàn)在它有效了
或者獲取 symbol.description 屬性,只顯示描述(description):
let id = Symbol("id");
alert(id.description); // id
“隱藏”屬性
symbol 允許創(chuàng)建對(duì)象的“隱藏”屬性,代碼的任何其他部分都不能意外訪問(wèn)或重寫(xiě)這些屬性。
例如,如果使用的是屬于第三方代碼的 user 對(duì)象,想要給它們添加一些標(biāo)識(shí)符。
可以給它們使用 symbol 鍵:
let user = { // 屬于另一個(gè)代碼
name: "John"
};
let id = Symbol("id");
user[id] = 1;
alert( user[id] ); // 我們可以使用 symbol 作為鍵來(lái)訪問(wèn)數(shù)據(jù)
使用 Symbol("id") 作為鍵,比起用字符串 "id" 來(lái)有什么好處呢?
由于 user 對(duì)象屬于另一個(gè)代碼庫(kù),所以向它們添加字段是不安全的,因?yàn)槲覀兛赡軙?huì)影響代碼庫(kù)中的其他預(yù)定義行為。但 symbol 屬性不會(huì)被意外訪問(wèn)到。第三方代碼不會(huì)知道新定義的 symbol,因此將 symbol 添加到 user 對(duì)象是安全的。
另外,假設(shè)另一個(gè)腳本希望在 user 中有自己的標(biāo)識(shí)符,以實(shí)現(xiàn)自己的目的。
那么,該腳本可以創(chuàng)建自己的 Symbol("id"),像這樣:
// ... let id = Symbol("id"); user[id] = "Their id value";
我們的標(biāo)識(shí)符和它們的標(biāo)識(shí)符之間不會(huì)有沖突,因?yàn)?symbol 總是不同的,即使它們有相同的名字。
……但如果我們處于同樣的目的,使用字符串 "id" 而不是用 symbol,那么 就會(huì) 出現(xiàn)沖突:
let user = { name: "John" };
// 我們的腳本使用了 "id" 屬性。
user.id = "Our id value";
// ……另一個(gè)腳本也想將 "id" 用于它的目的……
user.id = "Their id value"
// 砰!無(wú)意中被另一個(gè)腳本重寫(xiě)了 id!
對(duì)象字面量中的 symbol
如果我們要在對(duì)象字面量 {...} 中使用 symbol,則需要使用方括號(hào)把它括起來(lái)。
就像這樣:
let id = Symbol("id");
let user = {
name: "John",
[id]: 123 // 而不是 "id":123
};
symbol 在 for…in 中會(huì)被跳過(guò)
symbol 屬性不參與 for..in 循環(huán)。
let id = Symbol("id");
let user = {
name: "John",
age: 30,
[id]: 123
};
for (let key in user) alert(key); // name, age(沒(méi)有 symbol)
// 使用 symbol 任務(wù)直接訪問(wèn)
alert("Direct: " + user[id]); // Direct: 123
Object.keys(user) 也會(huì)忽略它們。這是一般“隱藏符號(hào)屬性”原則的一部分。如果另一個(gè)腳本或庫(kù)遍歷我們的對(duì)象,它不會(huì)意外地訪問(wèn)到符號(hào)屬性。
相反,Object.assign 會(huì)同時(shí)復(fù)制字符串和 symbol 屬性:
let id = Symbol("id");
let user = {
[id]: 123
};
let clone = Object.assign({}, user);
alert( clone[id] ); // 123
總結(jié)
symbol 是唯一標(biāo)識(shí)符的基本類型
symbol 是使用帶有可選描述(name)的 Symbol() 調(diào)用創(chuàng)建的。
symbol 總是不同的值,即使它們有相同的名字。如果我們希望同名的 symbol 相等,那么我們應(yīng)該使用全局注冊(cè)表:Symbol.for(key) 返回(如果需要的話則創(chuàng)建)一個(gè)以 key 作為名字的全局 symbol。使用 Symbol.for 多次調(diào)用 key 相同的 symbol 時(shí),返回的就是同一個(gè) symbol。
symbol 有兩個(gè)主要的使用場(chǎng)景:
-
“隱藏” 對(duì)象屬性。
如果我們想要向“屬于”另一個(gè)腳本或者庫(kù)的對(duì)象添加一個(gè)屬性,我們可以創(chuàng)建一個(gè) symbol 并使用它作為屬性的鍵。symbol 屬性不會(huì)出現(xiàn)在
for..in中,因此它不會(huì)意外地被與其他屬性一起處理。并且,它不會(huì)被直接訪問(wèn),因?yàn)榱硪粋€(gè)腳本沒(méi)有我們的 symbol。因此,該屬性將受到保護(hù),防止被意外使用或重寫(xiě)。因此我們可以使用 symbol 屬性“秘密地”將一些東西隱藏到我們需要的對(duì)象中,但其他地方看不到它。
-
JavaScript 使用了許多系統(tǒng) symbol,這些 symbol 可以作為
Symbol.*訪問(wèn)。我們可以使用它們來(lái)改變一些內(nèi)建行為。例如,在本教程的后面部分,我們將使用Symbol.iterator來(lái)進(jìn)行 迭代 操作,使用Symbol.toPrimitive來(lái)設(shè)置 對(duì)象原始值的轉(zhuǎn)換 等等。
從技術(shù)上說(shuō),symbol 不是 100% 隱藏的。有一個(gè)內(nèi)建方法 Object.getOwnPropertySymbols(obj) 允許我們獲取所有的 symbol。還有一個(gè)名為 Reflect.ownKeys(obj) 的方法可以返回一個(gè)對(duì)象的 所有 鍵,包括 symbol。但大多數(shù)庫(kù)、內(nèi)建方法和語(yǔ)法結(jié)構(gòu)都沒(méi)有使用這些方法。
浙公網(wǎng)安備 33010602011771號(hào)