### 概述
ES6引入了`Symbol`類型,它可以保證對象的屬性名始終唯一,不會造成命名沖突的問題。
`Symbol`是一種原始數據類型,表示獨一無二的值。它是JavaScript的第7種數據類型,前面6種分別是:`Undefined`、`Null`、布爾值(`Boolean`)、字符串(`String`)、數值(`Number`)和對象(`Object`)
`Symbol`值通過`Symbol`函數生成,對象的屬性名現在可以有兩種類型:一是原有的字符串類型,另一種就是新增的`Symbol`類型。
```js
let s = Symbol()
typeof s // 'symbol'
```
`Symbol`函數可以接受一個字符串作為參數,表示對`Symbol`實例的描述。
```js
let s1 = Symbol('foo')
let s2 = Symbol('bar')
s1 // Symbol(foo)
s2 // Symbol(bar)
```
### 作為屬性名的Symbol
由于每一個`Symbol`值都是不相等的,所以`Symbol`值可以作為標識符用于對象的屬性名,保證不會出現同名的屬性。
```js
let mySymbol = Symbol()
// 第一種寫法
let a = {}
a[mySymbol] = 'Hello'
// 第二種寫法
let a = {
[mySymbol]: 'Hello'
}
// 第三種寫法
let a = {}
Object.defineProperty(a, mySymbol, { value: 'Hello' })
// 以上寫法都得到同樣結果
a[mySymobl] // 'Hello'
```
**注意:** `Symbol`值作為對象屬性名時不能使用點(.)運算符
### 消除魔術字符串
魔術字符串指的是,在代碼之中多次出現,與代碼形成強耦合的某一個具體的字符串或數值。風格良好的代碼,應該消除魔術字符串,而由含義清晰的變量替代
```js
function getArea (shape, opitions) {
var area = 0
switch (shape) {
case 'Triangle': // 魔術字符串
area = '...'
break
/* more code */
}
return area
}
getArea('Triangle', { width: 100, height: 100 }) // 魔術字符串
```
使用`Symbol`改造如下:
```js
const shapeType = {
triangle: Symbol()
}
function getArea (shape, opitions) {
var area = 0
switch (shape) {
case shapeType.triangle:
area = '...'
break
/* more code */
}
return area
}
getArea(ShapeType.triangle, { width: 100, height: 100 })
```
### 屬性名的遍歷
`Symbol`作為屬性名,該屬性不會出現在`for...in`、`for...of`循環中,也不會被`Object.keys()`、`Object.getOwnPropertyNames()`返回,但有一個`Object.getOwnPropertySymbols`方法可以獲取指定對象的所有`Symbol`屬性名
`Object.getOwnPropertySymbols`方法返回一個數組,成員是當前對象的所有用作屬性名的`Symbol`值
```js
let obj = {}
let a = Symbol('a')
let b = Symbol('b')
obj[a] = 'Hello'
obj[b] = 'World'
let objectSymbols = Object.getOwnPropertySymbols(obj)
objectSymbols // [Symbol(a), Symbol(b)]
```
另外有一個新的API:`Reflect.ownKeys`方法可以返回所有類型的鍵名,包括常規鍵名和`Symbol`鍵名
### Symbol.for()、Symbol.keyFor()
`Symbol.for()`方法可以讓我們重復使用一個`Symobl`值,,它接受一個字符串作為參數,然后搜索有沒有以該參數作為名稱的`Symbol`值,如果有,則返回這個`Symbol`值,否則就新建并返回以該字符串作為名稱的`Symbol`值
```js
let s1 = Symbol.for('foo')
let s2 = Symbol.for('foo')
s1 === s2 // true
```
### 內置的Symbol值
ES6提供了11個內置的`Symbol`值。
#### Symbol.hasInstance
對象的`Symbol.hasInstance`屬性指向一個內部方法,對象使用`instanceof`運算符時會調用這個方法,判斷該對象是否為某個構造函數的實例。
```js
class MyClass {
[Symbol.hasInstance](foo) {
return foo instanceof Array
}
}
[1, 2, 3] instanceof new MyClass() // true
```
#### Symbol.isConcatSpreadable
對象的`Symbol.isConcatSpreadable`屬性等于一個布爾值,表示該對象使用`Array.prototype.concat()`方法時是否可以展開。
#### Symbol.species
對象的`Symbol.species`屬性指向當前對象的構造函數
#### Symbol.match
對象的`Symbol.match`屬性指向一個函數,當執行`str.match(myObject)`時,如果該屬性存在,會調用它返回該方法的返回值。
#### Symbol.replace
對象的`Symbol.replace`屬性指向一個方法,當對象被`String.prototype.replace`方法調用時會返回該方法的返回值
#### Symbol.search
#### Symbol.split
#### Symbol.iterator
#### Symbol.toPrimitive
#### Symbol.toStringTag
#### Symbol.unscopables