概述
ES5 的對象屬性名都是字符串,這容易造成屬性名的沖突。比如,你使用了一個他人提供的對象,但又想為這個對象添加新的方法(mixin 模式),新方法的名字就有可能與現有方法產生沖突。如果有一種機制,保證每個屬性的名字都是獨一無二的就好了,這樣就從根本上防止屬性名的沖突。這就是 ES6 引入Symbol
的原因。
ES6 引入了一種新的原始數據類型Symbol
,表示獨一無二的值。它是 JavaScript 語言的第七種數據類型,前六種是:undefined
、null
、布爾值(Boolean)、字符串(String)、數值(Number)、對象(Object)。
Symbol 值通過Symbol
函數生成。這就是說,對象的屬性名現在可以有兩種類型,一種是原來就有的字符串,另一種就是新增的 Symbol 類型。凡是屬性名屬於 Symbol 類型,就都是獨一無二的,可以保證不會與其他屬性名產生沖突。
let s = Symbol(); typeof s // "symbol"
上面代碼中,變量s
就是一個獨一無二的值。typeof
運算符的結果,表明變量s
是 Symbol 數據類型,而不是字符串之類的其他類型。
注意,Symbol
函數前不能使用new
命令,否則會報錯。這是因為生成的 Symbol 是一個原始類型的值,不是對象。也就是說,由於 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 的參數是一個對象,就會調用該對象的toString
方法,將其轉為字符串,然后才生成一個 Symbol 值。
const obj = { toString() { return 'abc'; } }; const sym = Symbol(obj); sym // Symbol(abc)
注意,Symbol
函數的參數只是表示對當前 Symbol 值的描述,因此相同參數的Symbol
函數的返回值是不相等的。