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 入門