根據(jù)規(guī)范晾蜘,對象的屬性鍵只能是字符串類型或者 Symbol 類型,到目前為止仗考,我們只見過字符串。現(xiàn)在我們來看看 Symbol 能給我們帶來什么好處词爬。
1秃嗜、symbol值表示唯一的標(biāo)識符,即使創(chuàng)建了許多具有相同描述的symbol顿膨,它們的值也不相同锅锨,描述只是一個(gè)標(biāo)簽,不影響任何東西
let id1 = Symbol("id")
let id2 = Symbol("id")
alert(id1==id2) // false
2恋沃、symbol不會(huì)被自動(dòng)轉(zhuǎn)換為字符串
let id = Symbol("id")
alert(id) //?Cannot convert a Symbol value to a string
這是一種防止混亂的“語言保護(hù)”必搞,因?yàn)樽址?Symbol 有本質(zhì)上的不同,不應(yīng)該意外地將它們轉(zhuǎn)換成另一個(gè)芽唇。
let id = Symbol("id")
alert(id.toString())? //?Symbol(id)
或者獲取?symbol.description?屬性,只顯示描述(description):
let id = Symbol("id")
alert(id.description) // id
3、隱藏屬性
Symbol 允許我們創(chuàng)建對象的“隱藏”屬性匆笤,代碼的任何其他部分都不能意外訪問或重寫這些屬性研侣。
let?user?=?{?//?屬于另一個(gè)代碼
????name:?"John",
????id:?'7777777777'
??};
??let?id?=?Symbol("id");
??user[id]?=?1;
??console.log(user) //?{name: "John", id: '7777777777', Symbol(id): 1}
? console.log(user[id]) // 1?
? console.log(user.id) //?7777777777
使用?Symbol("id")?作為鍵,比起用字符串?"id"?來有什么好處呢炮捧?
因?yàn)?user?對象屬于其他的代碼庶诡,那些代碼也會(huì)使用這個(gè)對象,所以我們不應(yīng)該在它上面直接添加任何字段咆课,這樣很不安全末誓。但是你添加的 Symbol 屬性不會(huì)被意外訪問到,第三方代碼根本不會(huì)看到它书蚪,所以使用 Symbol 基本上不會(huì)有問題喇澡。
另外,假設(shè)另一個(gè)腳本希望在?user?中有自己的標(biāo)識符殊校,以實(shí)現(xiàn)自己的目的晴玖。這可能是另一個(gè) JavaScript 庫,因此腳本之間完全不了解彼此为流。
然后該腳本可以創(chuàng)建自己的?Symbol("id")
我們的標(biāo)識符和它們的標(biāo)識符之間不會(huì)有沖突呕屎,因?yàn)?Symbol 總是不同的,即使它們有相同的名字敬察。
……但如果我們處于同樣的目的秀睛,使用字符串?"id"?而不是用 symbol,那么?就會(huì)?出現(xiàn)沖突
4莲祸、對象字面量中的Symbol蹂安,如果我們要在對象字面量?{...}?中使用 Symbol,則需要使用方括號把它括起來虫给。
let id = Symbol("id")
let user = { name: "John",[id]:123}
5藤抡、Symbol 屬性不參與?for..in?循環(huán)
Object.keys(user)?也會(huì)忽略它們。這是一般“隱藏符號屬性”原則的一部分抹估。如果另一個(gè)腳本或庫遍歷我們的對象缠黍,它不會(huì)意外地訪問到符號屬性。
相反药蜻,Object.assign?會(huì)同時(shí)復(fù)制字符串和 symbol 屬性:
let id = Symbol("id")
let user = { [id]: 123}
let clone = Object.assign({}, user)
alert( clone[id] ); // 123
6瓷式、全局Symbol
// 從全局注冊表中讀取
let id = Symbol.for("id")// 如果該 Symbol 不存在,則創(chuàng)建它
// 再次讀扔镌蟆(可能是在代碼中的另一個(gè)位置)
let idAgain = Symbol.for("id") // 相同的?
Symbolalert( id === idAgain ); // true
注冊表內(nèi)的 Symbol 被稱為?全局 Symbol贸典。如果我們想要一個(gè)應(yīng)用程序范圍內(nèi)的 Symbol,可以在代碼中隨處訪問 —— 這就是它們的用途踱卵。
7廊驼、Symbol.keyFor
對于全局 Symbol据过,不僅有?Symbol.for(key)?按名字返回一個(gè) Symbol,還有一個(gè)反向調(diào)用:Symbol.keyFor(sym)妒挎,它的作用完全反過來:通過全局 Symbol 返回一個(gè)名字绳锅。
// 通過 name 獲取 Symbol
let sym = Symbol.for("name")
let sym2 = Symbol.for("id") // 通過 Symbol 獲取 name
alert( Symbol.keyFor(sym) ); // name
alert( Symbol.keyFor(sym2) ); // id
Symbol.keyFor?內(nèi)部使用全局 Symbol 注冊表來查找 Symbol 的鍵。所以它不適用于非全局 Symbol酝掩。如果 Symbol 不是全局的鳞芙,它將無法找到它并返回?undefined。
也就是說期虾,任何 Symbol 都具有?description?屬性原朝。
let globalSymbol = Symbol.for("name");
let localSymbol = Symbol("name");
alert( Symbol.keyFor(globalSymbol) ); // name,全局 Symbol
alert( Symbol.keyFor(localSymbol) ); // undefined镶苞,非全局
alert( localSymbol.description ); // name
8浊竟、系統(tǒng)Symbol
JavaScript 使用了許多系統(tǒng) Symbol撰筷,這些 Symbol 可以作為?Symbol.*?訪問魔慷。我們可以使用它們來改變一些內(nèi)置行為雹舀。