JS之路 Day19 - What is symbol?
前言
ES6 才加入的primitive type
,我個人覺得是primitive type
當中最難理解的。
object
的key
在 ES6 之前都只能是字串,就算寫成數字也會被轉成字串,所以之前我會說,object
的key
只能是字串,但這個說法被symbol
打破了,它也可以拿來當作object
的key
,而它為什麼可以,以及symbol
是處理什麼領域的問題,讓我們看下去吧。
特性:獨一無二
symbol
可以直接跟獨一無二的值劃上等號,只會有一個保證是唯一的,這其實就是可以拿來當作object
的key
的原因,不會重複很適合拿來幫物件取名。
這樣記:只要透過symbol
建立的值,都會獲得特性:獨一無二
。
建立:symbol
建立symbol
的方式很簡單,只要使用Symbol()
即可,不需要用new
。
1 | // 語法 |
可以給Symbol
裡面加名字,在Symbol()
的()
裡面,可以當作它是這個變數fruit
的描述,而它的類別是Symbol
。
由於特性:獨一無二
,所以當名字都是取一樣的,實際上值也是不同的,名字僅供參考,像是:
1 | const fruit = Symbol("apple"); |
招式:Symbol.for()、Symbol.keyFor()
所有的Symbol
都是不同的,就算名字都取的一樣,但有時候還是會想要說相同名字的Symbol
能夠擁有相同的實體,為了做到這件事情,需要一個名為global Symbol registry
的概念。
想像有一個神秘的空間(註冊表),創建了Symbol
會註冊在裡面,想去看的時後可以隨時訪問,但不是想看就看的,需要名為招式Symbol.for()
才辦到的。
要在註冊表裡讀取symbol
,需要使用Symbol.for()
。
Symbol.for()
相當於創立Symbol
,只是這個創立Symbol
是把它放到註冊表當中。
1 | const fruit = Symbol.for("apple"); |
比較一下:Symbol()
=> 每個創立都不相同(就算同名字),全域無法找到。Symbol.for()
=> 創立時會放到註冊表,同名字就當作相同創建,在全域可以被Symbol.keyFor()
找到。
而我要怎麼去拿到已經放到在註冊表裡面的symbol
?
就會需要另一個招式=> Symbol.keyFor()
1 | const fruit = Symbol("apple"); |
一樣直接創立的話,就不存在於global Symbol registry
,自然Symbol.keyFor()
就無法找到。
這兩個招式其實就是symbol
的Static methods
(靜態方法)。
排擠:symbol
可能是symbol
太有個性了(獨一無二),在某些場合,會發生symbol
被無視的狀況,比如說for..in
:
1 | const fruit = Symbol("apple"); |
不過還是能找到它裡面的值:
1 | console.log(user[fruit]); // this is a apple |
跟for..in
同個系列的for..of
也會被略過。
另外一個會排擠symbol
是Object.keys
:
遇到就直接無視。
1 | const fruit = Symbol("apple"); |
symbol
在for..in
、for..of
、Object.keys
都會被跳過。
可以反過來利用這個特性,當你想要隱藏某一些物件的屬性時,用symbol
當object
的key
就對了,它在上面那些狀況都不會與其他属性一起被處理。
reference
[1] MDN - Symbol
[2] JS Symbols 的使用
[3] ECMAScript 6 入門