# symbol

symbol是es6出的一种类型，他也是属于原始类型的范畴(string, number, boolean, null, undefined, symbol)

## basic

```javascript
let name = Symbol('xiaohesong')
typeof name // 'symbol'
let obj = {}
obj[name] = 'xhs'
console.log(obj[name]) //xhs
```

## symbol for

这个东西是可共享，在创建的时候会检查全局是否寻在这个key的symbol.如果存在就直接返回这个symbol,如果不存在就会创建，并且在全局注册。

```javascript
let uid = Symbol.for("uid");
let object = {
    [uid]: "12345"
};

console.log(object[uid]);       // "12345"
console.log(uid);               // "Symbol(uid)"

let uid2 = Symbol.for("uid");

console.log(uid === uid2);      // true
console.log(object[uid2]);      // "12345"
console.log(uid2);              // "Symbol(uid)"
```

> 此处所说的共享是全局性的共享，类似于global scope，是整个大环境下的共享.

## symbol keyfor

```javascript
let uid = Symbol.for("uid");
console.log(Symbol.keyFor(uid));    // "uid"

let uid2 = Symbol.for("uid");
console.log(Symbol.keyFor(uid2));   // "uid"

let uid3 = Symbol("uid");
console.log(Symbol.keyFor(uid3));   // undefined
```

全局注册表不存在uid3这个共享的symbol.所以取不出对应的key.由此可见，这个是获取对应的key.

## symbol 不可强制转换

```javascript
let uid = Symbol('uid')
uid + ''
```

这里会报错，根据规范，他会把uid转换成字符串进行相加。如果真的相加，可以先`String(uid)`之后再相加，不过目前看来，似乎没什么意义。

## obj中symbol key的获取

```javascript
let uid = Symbol('uid')
let obj = {
    [uid]: 'uid'
}

console.log(Object.keys(obj)) // []
console.log(Object.getOwnPropertyNames(obj)) // []
console.log(Object.getOwnPropertySymbols(obj)) // [Symbol(uid)]
```

es6针对这个，添加了`Object.getOwnPropertySymbols`方法。

是不是感觉很少用到Symbols.其实es6内部用的还是不少的。

## Symbol.hasInstance

每个函数都有这个方法。或许你对这个方法不是很熟，他其实就是`instanceof`所做的事情。 没错，es6给你重写了这个方法。

```javascript
function Xiao(){}
const xiao = new Xiao
xiao instanceof Xiao // true
```

实际上es6帮你那么干了

```javascript
 Xiao[Symbol.hasInstance](xiao)
```

这个是内部的方法，不支持重写，当然，我们可以在原型上改写。

```javascript
 Object.definePrototype(Xiao, Symbol.hasInstance, {
    value: (v) => Boolean(v)
 })
 const x = new Xiao
 x instanceof Xiao //true
 0 instanceof Xiao //false
 1 instanceof Xiao //true
```

可以发现，我们改写他返回对应的是否为boolean类型。

## Symbol.isConcatSpreadable

这个和其他的一些属性不同，他是默认不存在一些标准对象上。简单的使用

```javascript
 let objs = {0: 'first', 1: 'second', length: 2, [Symbol.isConcatSpreadable]: true}
 ['arrs'].concat(objs) //["arrs", "first", "second"]
```

## Symbol.toPrimitive

这个用的就多了，进行类型转换的时候，对象会进行尝试转换成原始类型，就是通过`toPrimitive`.这个方法，标准类型的原型上都存在。

进行类型转换的时候，`toPrimitive`会被强制的调用一个参数，在规范中这个参数被称之为`hint`. 这个参数是三个值('number', 'string', 'default')其中的一个。

顾名思义，`string`返回的是`string`, `number`返回的是`number`，`default`是没有特别指定，默认。

那么什么是默认的情况呢？ 大多数的情况下，默认情况就是数字模式。(日期除外，他的默认情况视为字符串模式)

其实在类型转换时调用默认情况的也不是很多。如(`==`, `+`)或者将参数传递给`Date`的构造参数的时候。

* number mode 在数字情况下的行为(优先级从高到低)
  * 首先调用`valueOf`，如果是一个原始类型，那就返回。
  * 如果前面不是原始值，那么就尝试调用`toString`，如果是原始值，那么就返回
  * 如果都不存在，那么就报错
* string mode 在字符串的情况下，行为略有不同(优先级从高到低)
  * 首先调用`toString`，如果是原始值，那么就返回
  * 如果前面不是原始值，那么就尝试调用`valueOf`，如果是原始值，那么就返回
  * 抛出错误

嗯，是不是感觉挺绕的，是啊，代码阐述下嘛。

```javascript
let obj = {
    valueOf: function(){console.log('valueOf')},
    toString: function(){console.log('toString')}
}
// console.log value is
obj + 2 //valueOf
obj == 2 // valueOf
Number(obj) // valueOf
String(obj) // toString
```

通过上面的输出，可以发现大多数的情况都是首先调用`valueOf`. 包括默认的情况，他的默认是调用的数字模式，而且绝大数都是调用的数字模式，可以发现`toString`是调用了`string`的模式。所以你可以认为，基本就是数字模式，除非很显示的是字符串模式。

对于这个调用的模式还不是很清楚？没事，es6把这个内部的方法对外暴露出来了，我们可以改写他，输出这个`hint`的类型。 来

```javascript
function Temperature(degrees) {
    this.degrees = degrees;
}

Temperature.prototype[Symbol.toPrimitive] = function(hint) {
    console.log('hint is', hint)
};

let freezing = new Temperature(32);

freezing + 2 // ..
freezing / 2 // ..
...
```

上面的类型，自己尝试吧。

## Symbo.species

这个需要联系class的上下文来阐述了，[点击此处](https://github.com/xiaohesong/til/blob/master/front-end/es6/understanding-es6/class.md#symbolspecies属性)查看详细


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://xiaohesong.gitbook.io/today-i-learn/front-end/es6/understanding-es6/symbol.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
