ES5 的對象屬性名都是字符串,這容易形成屬性名的衝突。好比,你使用了一個他人提供的對象,但又想爲這個對象添加新的方法(mixin 模式),新方法的名字就有可能與現有方法產生衝突。若是有一種機制,保證每一個屬性的名字都是獨一無二的就行了,這樣就從根本上防止屬性名的衝突。這就是 ES6 引入Symbol的緣由。
ES6
引入了一種新的原始數據類型Symbol
,表示獨一無二的值。它是 JavaScript
語言的第七種數據類型,前六種是:undefined、null、布爾值(Boolean)、字符串(String)、數值(Number)、對象(Object
)。app
let s = Symbol(); typeof s // "symbol"
Symbol
是一種獨特的且不可變的數據類型,常常用來標識對象屬性。code
要建立 Symbol
,輸入 Symbol()
,並添加一個可選的字符串做爲其描述。對象
const sym1 = Symbol('apple'); console.log(sym1); //Symbol(apple)
它將建立惟一的標識符,並將其存儲在 sym1
中。描述 "apple"
只是用來描述標識符的一種方式,可是不能用來訪問標識符自己。ip
若是對具備相同描述的兩個標識符進行比較……字符串
const sym2 = Symbol('banana'); const sym3 = Symbol('banana'); console.log(sym2 === sym3);
結果是 false
,由於描述只是用來描述符號,它並非標識符自己的一部分。不管描述是什麼,每次都建立新的標識符。get
Symbol
值不能與其餘類型的值進行運算,會報錯。可是,Symbol
值能夠顯式轉爲字符串。也能夠轉爲布爾值,可是不能轉爲數值。string
let sym = Symbol('My symbol'); "your symbol is " + sym // TypeError: can't convert symbol to string String(sym) // 'Symbol(My symbol)' sym.toString() // 'Symbol(My symbol)' Boolean(sym) // true !sym // false Number(sym) // TypeError sym + 2 // TypeError
因爲每個 Symbol 值都是不相等的,這意味着 Symbol 值能夠做爲標識符,用於對象的屬性名,就能保證不會出現同名的屬性
let mySymbol = Symbol(); // 第一種寫法 let a = {}; a[mySymbol] = 'Hello!'; // 第二種寫法 let a = { [mySymbol]: 'Hello!' }; a[mySymbol] // "Hello!"
注意,Symbol
值做爲對象屬性名時,不能用點運算符。同理,在對象的內部,使用 Symbol
值定義屬性時,Symbol
值必須放在方括號之中。console
Symbol
做爲屬性名,該屬性不會出如今for...in、for...of
循環中,也不會被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()
返回。可是,它也不是私有屬性,有一個Object.getOwnPropertySymbols
方法,能夠獲取指定對象的全部 Symbol
屬性名。class
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)]