# 了解一下 Symbol

# Symbol

Symbol 创建一个唯一值,即便传入的参数一样,两个 symbol 也毫不相干

let wzp = Symbol('wzpp')
let wzp1 = Symbol('wzpp')
console.log('typeof wzp: ', typeof wzp)
let obj = {}
obj[wzp] = 'obj-wzpp'
console.log('wzp1: ', wzp1)
console.log('wzp1 === wzp: ', wzp1 === wzp)
console.log('obj[wzp]: ', obj[wzp])
1
2
3
4
5
6
7
8

# Symbol.for

Symbol.for 会先在全局 Symbol 注册表寻找是否有重复 key,有的话直接返回,没有新建一个

let uid = Symbol.for('uid')
obj[uid] = '123'

console.log('obj[uid]: ', obj[uid])
console.log('uid: ', uid)

let uid2 = Symbol.for('uid')
console.log('uid === uid2: ', uid === uid2)
console.log('obj[uid2]: ', obj[uid2])
1
2
3
4
5
6
7
8
9

# Symbol.keyFor

在全局 Symbol 注册表寻找 Symbol 对应的 key 值 Symbol 可以理解在局部创建 Symbol 值 Symbol.for 可以理解在全局创建 Symbol 值,Symbol.keyFor 只能找到全局 Symbol 注册表的 key

console.log('Symbol.keyFor(uid): ', Symbol.keyFor(uid)) // 'uid'
console.log('Symbol.keyFor(wzpp): ', Symbol.keyFor(wzp)) // undefined
1
2

# Symbol 不可强制转换

uid + '' // TypeError: Cannot convert a Symbol value to a string
1

# getOwnPropertySymbols 方法

获取对象中 Symbol 类型的 key 值

console.log(
  'Object.getOwnPropertySymbols(obj): ',
  Object.getOwnPropertySymbols(obj)
)
1
2
3
4

# Symbol.hasInstance

每个函数都有这个方法,其实就是 instanceof 做的事情

function F() {}
const f = new F()
console.log('F[Symbol.hasInstance](f): ', F[Symbol.hasInstance](f))
1
2
3

内部方法,不支持重写,但我们可以在原型改

F[Symbol.hasInstance] = (v) => Boolean(v) // 重写无效
console.log('1 instanceof F: ', 1 instanceof F) // 有效 true 无效 false 理想值:true 实际值:false
Object.defineProperty(F, Symbol.hasInstance, { value: (v) => Boolean(v) }) //原型修改
console.log('1 instanceof F: ', 1 instanceof F) // 有效 true 无效 false 理想值:true 实际值:true
1
2
3
4

# Symbol.isConcatSpreadable

该属性决定是否支持 concat

let objs = {
  0: 'obj-item1',
  1: 'obj-item2',
  length: 2,
  [Symbol.isConcatSpreadable]: true
} // 类数组
console.log('["arr-item0"].concat(objs): ', ['arr-item0'].concat(objs))
1
2
3
4
5
6
7

# Symbol.toPrimitive

  • 标准类型的原型上都存在该方法,比如 对象尝试转为原始值的时候就会调用该方法
  • 在进行类型转换的时候,会传入一个参数,规范将该参数叫做 hint
  • hint 取值为('number','string','default')
    • number => number
    • string => string
    • default => 默认
  • 大多数默认的情况就是数字模式(除了日期,它默认是字符串模式)
  • number mode(数字模式)行为情况(优先级从高到低)
    • 首先调用 valueOf,如果是原始值,则返回
    • 如果不是原始值,则调用 toString,如果是原始值,则返回
    • 如果不是原始值,报错
  • string mode(字符串模式)行为情况(优先级从高到低)
    • 首先调用 toString,如果是原始值,则返回
    • 如果不是原始值,则调用 valueOf,如果是原始值,则返回
    • 如果不是原始值,报错
let objp = {
  valueOf: function() {
    console.log('valueOf')
  },
  toString: function() {
    console.log('toString')
  }
}
// console.log value is
objp + 2 //valueOf
objp == 2 // valueOf
Number(objp) // valueOf
String(objp) // toString
1
2
3
4
5
6
7
8
9
10
11
12
13

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

# Symbol.species

这个需要联系 class 的上下文来阐述了,传送门

# Symbol.iterator

我们知道可以通过for .. in来获取对象的属性名字,而for .. of是获取对应的value.

并且for .. of是需要iterable才可以。

// example1
let arr = ['wzp']
let it = ar[Symbol.iterator]()
it // Array Iterator
it.next() // {value: "wzp", done: false}
it.next() // {value: undefined, done: true}

//example2
let str = 'string'
let it = str[Symbol.iterator]()
it // StringIterator

// example3
let o = { name: 'wzp' }
let obj = o[Symbol.iterator]() //Uncaught TypeError: o[Symbol.iterator] is not a function
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

对象不可用for..of来遍历,因为没有Symbol.iterator方法,我们给对象手动添加这个方法

let range = {
  from: 1,
  to: 5
}

// 我们想要的效果:
// for(let num of range) ... num=1,2,3,4,5
1
2
3
4
5
6
7

改写:

let range = {
  from: 1,
  to: 5
}

// 1. for..of 默认调用iterator
range[Symbol.iterator] = function() {
  // 2. 返回一个遍历器对象:
  return {
    current: this.from,
    last: this.to,

    // 3.在for..of每次循环会调用next函数
    next() {
      // 4. 返回一个对象形如 {done:.., value :...}
      if (this.current <= this.last) {
        return { done: false, value: this.current++ }
      } else {
        return { done: true }
      }
    }
  }
}

// 现在就可以遍历该对象了
for (let num of range) {
  alert(num) // 1, then 2, 3, 4, 5
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 参考

symbol (opens new window)

最近更新: 4 小时前