### 概述
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