前言

ES6 才加入的primitive type,我個人覺得是primitive type當中最難理解的。

objectkey在 ES6 之前都只能是字串,就算寫成數字也會被轉成字串,所以之前我會說,objectkey只能是字串,但這個說法被symbol打破了,它也可以拿來當作objectkey,而它為什麼可以,以及symbol是處理什麼領域的問題,讓我們看下去吧。

特性:獨一無二

symbol可以直接跟獨一無二的值劃上等號,只會有一個保證是唯一的,這其實就是可以拿來當作objectkey的原因,不會重複很適合拿來幫物件取名。

這樣記:只要透過symbol建立的值,都會獲得特性:獨一無二

建立:symbol

建立symbol的方式很簡單,只要使用Symbol()即可,不需要用new

1
2
3
4
// 語法
const fruit = Symbol();

console.log(typeof symbol); // symbol

可以給Symbol裡面加名字,在Symbol()()裡面,可以當作它是這個變數fruit的描述,而它的類別是Symbol

由於特性:獨一無二,所以當名字都是取一樣的,實際上值也是不同的,名字僅供參考,像是:

1
2
3
4
const fruit = Symbol("apple");
const fruit2 = Symbol("apple");

console.log(fruit == fruit2); // false

招式:Symbol.for()、Symbol.keyFor()

所有的Symbol都是不同的,就算名字都取的一樣,但有時候還是會想要說相同名字的Symbol能夠擁有相同的實體,為了做到這件事情,需要一個名為global Symbol registry的概念。

想像有一個神秘的空間(註冊表),創建了Symbol會註冊在裡面,想去看的時後可以隨時訪問,但不是想看就看的,需要名為招式Symbol.for()才辦到的。

要在註冊表裡讀取symbol,需要使用Symbol.for()

Symbol.for()相當於創立Symbol,只是這個創立Symbol是把它放到註冊表當中。

1
2
3
4
const fruit = Symbol.for("apple");
const fruit2 = Symbol.for("apple");

console.log(fruit == fruit2); // true

比較一下
Symbol() => 每個創立都不相同(就算同名字),全域無法找到。
Symbol.for() => 創立時會放到註冊表,同名字就當作相同創建,在全域可以被Symbol.keyFor()找到。

而我要怎麼去拿到已經放到在註冊表裡面的symbol
就會需要另一個招式=> Symbol.keyFor()

1
2
3
4
5
const fruit = Symbol("apple");
const fruit2 = Symbol.for("apple");

console.log(Symbol.keyFor(fruit)); // undefined
console.log(Symbol.keyFor(fruit2)); // apple

一樣直接創立的話,就不存在於global Symbol registry,自然Symbol.keyFor()就無法找到。

這兩個招式其實就是symbolStatic methods(靜態方法)。

排擠:symbol

可能是symbol太有個性了(獨一無二),在某些場合,會發生symbol被無視的狀況,比如說for..in

1
2
3
4
5
6
7
8
const fruit = Symbol("apple");
const user = {
name: "vic",
age: 23,
[fruit]: "this is a apple",
};

for (const key in user) console.log(key); // name, age 沒有 fruit

不過還是能找到它裡面的值:

1
console.log(user[fruit]); // this is a apple

for..in同個系列的for..of也會被略過。

另外一個會排擠symbolObject.keys:

遇到就直接無視。

1
2
3
4
5
6
7
8
9
const fruit = Symbol("apple");

const obj = {
a: 1,
b: 2,
[fruit]: "this is a apple",
};

console.log(Object.keys(obj)); // [ 'a', 'b' ]

symbolfor..infor..ofObject.keys都會被跳過。

可以反過來利用這個特性,當你想要隱藏某一些物件的屬性時,用symbolobjectkey就對了,它在上面那些狀況都不會與其他属性一起被處理。

reference

[1] MDN - Symbol
[2] JS Symbols 的使用
[3] ECMAScript 6 入門