ES5 的對象屬性名都是字符串,這容易形成屬性名的衝突。好比,你使用了一個他人提供的對象,但又想爲這個對象添加新的方法(mixin 模式),新方法的名字就有可能與現有方法產生衝突。若是有一種機制,保證每一個屬性的名字都是獨一無二的就行了,這樣就從根本上防止屬性名的衝突。這就是 ES6 引入Symbol的緣由。即Symbol是爲了解決對象屬性名衝突問題。es6
Symbol是es6引入的一種新的數據類型,表示獨一無二的值。至此js共有7種數據類型,其中值類型爲:undefined、null、布爾值(Boolean)、字符串(String)、數值(Number)、符號(Symbol)和引用類型:對象(Object)。函數
執行Symbol([description])函數能夠生成一個與其餘Symbol值互不相等的獨一無二的Symbol值code
const sym = Symbol() // Symbol() const symWithNumber = Symbol(3.14) // Symbol(3.14) const symWithObject = Symbol({foo:'bar'}) // Symbol([object,object])
其中Symbol()函數接受一個可選的除Symbol值之外的值做爲對該Symbol值的描述。這個描述值僅僅起到描述的做用,而不會對Symbol值自己產生任何影響。對象
const symWithSymbol = Symbol(sym) // TypeError: Cannot convert a Symbol value to a string const sym1 = Symbol('foo') const sym2 = Symbol('foo') sym1 === sym2 // false
Symbol()函數不是一個構造函數,前面不能加new關鍵字,不然會報錯ip
new Symbol() // TypeError: Symbol is not a constructor
對象的屬性名如今能夠有兩種類型,一種是原來就有的字符串,另外一種就是新增的 Symbol 類型。
當Symbol值做爲對象的屬性名時,要用方括號[],不然會被看成字符串處理作用域
let sym = Symbol(); // 第一種寫法 let a = {}; a[sym] = 'Hello!'; // 第二種寫法 let a = { [sym]: 'Hello!' }; // 第三種寫法 let a = {}; Object.defineProperty(a, sym, { value: 'Hello!' }); // 以上寫法都獲得一樣結果 a[sym] // "Hello!"
Symbol 做爲屬性名,遍歷對象的時候,該屬性不會出如今for...in、for...of循環中,也不會被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回。字符串
Object.getOwnPropertySymbols()方法能夠獲取全部 Symbol 屬性名,get
另外一個新的 API,Reflect.ownKeys()方法能夠返回全部類型的鍵名,包括常規鍵名和 Symbol 鍵名字符串處理
Symbol.for([key])與Symbol([description])都會生成Symbol值,它們的區別是,Symbol.for([key])會根據傳入的key(字符串類型)在全局做用域中註冊一個Symbol值,若是某個key從未被註冊到全局做用域中,便會建立一個Symbol值並根據key註冊到全局做用域中。若是該key已被註冊,則會返回一個和第一次使用所建立的Symbol值等價的Symbol值。而Symbol([description])每一次調用都會返回不一樣的Symbol值。string
const sym1 = Symbol.for('foo') const sym2 = Symbol.for('foo') sym1 === sym2 // true
既然能夠根據字符串的key在全局環境中註冊一個全局Symbol值,那麼一樣也能夠到這些全局Symbol值對應的key值。
const sym = Symbol.for('foo') console.log(Symbol.keyFor(sym)) // foo