目錄
- 概述
- Symbol可以傳參數
- Symbol 作為屬性名的用法
- Symbol.for()
1.為什麼要有Symbol
ES5 的對象屬性名都是字元串,這容易造成屬性名的沖突。比如,你使用了一個他人提供的對象,但又想為這個對象添加新的方法(mixin 模式),新方法的名字就有可能與現有方法産生沖突。如果有一種機制,保證每個屬性的名字都是獨一無二的就好了,這樣就從根本上防止屬性名的沖突。這就是 ES6 引入
Symbol
的原因。
ES6 引入了一種新的原始資料類型
Symbol
,表示獨一無二的值。它是 JavaScript 語言的第七種資料類型,前六種是:
undefined
、
null
、布爾值(Boolean)、字元串(String)、數值(Number)、對象(Object)。
Symbol 值通過
Symbol
函數生成。這就是說,對象的屬性名現在可以有兩種類型,一種是原來就有的字元串,另一種就是新增的 Symbol 類型。凡是屬性名屬于 Symbol 類型,就都是獨一無二的,可以保證不會與其他屬性名産生沖突。
注意,Symbol函數前不能使用new指令,否則會報錯。這是因為生成的 Symbol 是一個原始類型的值,不是對象。也就是說,由于 Symbol 值不是對象,是以不能添加屬性。基本上,它是一種類似于字元串的資料類型。
let s = Symbol();
2. Symbol可以傳參數
Symbol
函數可以接受一個字元串作為參數,表示對
Symbol
執行個體的描述,主要是為了在控制台顯示,或者轉為字元串時,比較容易區分。
let s1 = Symbol('foo');
let s2 = Symbol('bar');
s1 // Symbol(foo)
s2 // Symbol(bar)
s1.toString() // "Symbol(foo)"
s2.toString() // "Symbol(bar)"
上面代碼中,
s1
和
s2
是兩個
Symbol
值。如果不加參數,它們在控制台的輸出都是
Symbol()
,不利于區分。有了參數以後,就等于為它們加上了描述,輸出的時候就能夠厘清,到底是哪一個值。
注意,
Symbol
函數的參數隻是表示對目前
Symbol
值的描述,是以相同參數的
Symbol
函數的傳回值是不相等的。
// 沒有參數
let s1 = Symbol();
let s2 = Symbol();
s1 === s2; //false
// 有參數的情況
let s3 = Symbol('foo');
let s4 = Symbol('foo');
s3 === s4; // false
3. Symbol 作為屬性名的用法
由于每一個
Symbol
值都是不相等的,這意味着
Symbol
值可以作為辨別符,用于對象的屬性名,就能保證不會出現同名的屬性。這對于一個對象由多個子產品構成的情況非常有用,能防止某一個鍵被不小心改寫或覆寫。
let s = Symbol();
// 第一種寫法
let a = {
[s]: 'hello'
}
// 第二種寫法
let a = {};
a[s] = 'hello';
// 第三種寫法
let a = {};
Object.defineProperty(a, s, {value: 'hello'});
// 以上寫法都會得到相同的結果
a[s] = 'hello';
注意,
Symbol
值作為對象屬性名時,不能用點運算符,隻能用中括号([])。
a.s = 'hello'; // 會将 s 當做字元串來處理,而不是 Symbol 資料格式
a[s]; // undefined
注意:
Symbol
作為屬性名,該屬性不會出現在
for...in
、
for...of
循環中,也不會被
Object.keys()
、
Object.getOwnPropertyNames()
、
JSON.stringify()
傳回。
但是,它也不是私有屬性,有一個
Object.getOwnPropertySymbols
方法,可以擷取指定對象的所有
Symbol
屬性名。
const obj = {};
let a = Symbol('a');
let b = Symbol('b');
obj[a] = 'Hello';
obj[b] = 'World';
const objectSymbols = Object.getOwnPropertySymbols(obj);
objectSymbols
// [Symbol(a), Symbol(b)]
4. Symbol.for()
有時,我們希望重新使用同一個
Symbol
值,
Symbol.for
方法可以做到這一點。它接受一個字元串作為參數,然後搜尋有沒有以該參數作為名稱的
Symbol
值。如果有,就傳回這個
Symbol
值,否則就建立并傳回一個以該字元串為名稱的
Symbol
值。
let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');
s1 === s2; // true
// 注意對比 Symbol()
let s3 = Symbol('bar');
let s4 = Symbol('bar');
s3 === s4; // false