Symbol的简单学习

125 阅读3分钟

这是我参与11月更文挑战的第14天,活动详情查看:2021最后一次更文挑战

缘由

es6新增了一个基本类型,叫Symbol,代表的是独一无二的值,每一个symbol都是不相等的,这样如果你把它作为对象的key值,就代表是唯一的,不会产生同名字符串做key导致值被覆盖问题。

今天来学学它的语法和常用的用法。

Symbol

语法

Symbol(value)

value是可选的

let symbol = Symbol()
console.log(symbol) // Symbol()

let name = Symbol('答案cp3')
console.log(name) // Symbol(答案cp3)
typeof name // 'symbol'

通过一个Symbol函数,传入value,生成一个symbol值,它的typeof 就是symbol

这个函数不是构造函数,所以不能使用new

let name1 = new Symbol('答案cp3') // error:  Symbol is not a constructor

symbol就算value是一样的,也不是同一个,它们是不相等的。

let name = Symbol('答案cp3')
let name1 = Symbol('答案cp3')
console.log(name === name1) // false

value可以是基本类型,比如字符串,数字,布尔等,也可以是对象,

如果是对象,会调用它的toString方法的返回值来生成symbol

let num = Symbol(1)
console.log(num) // 'Symbol(1)'

let bool = Symbol(false)
console.log(bool) // 'Symbol(false)'

// 调用toString方法
let obj = Symbol({})
console.log(obj) // Symbol([object Object])

// 重写toString方法
let obj1 = {
 toString() {
   return '答案cp3'
 }
}
console.log(Symbol(obj1)) // Symbol(答案cp3)

知识点

  1. 生成的symbol,我们可以通过它的description属性拿到它的value值。
let name = Symbol('答案cp3')
console.log(name.description) // 答案cp3
  1. 上面说了,symbol生成的值都是独一无二的,可以用作对象的key值。
let obj = {}
let a1 = Symbol('a')
let a2 = Symbol('a')
obj[a1] = 'symbol1'
obj[a2] = 'symbol2'
console.log(obj) // {Symbol(a): 'symbol1', Symbol(a): 'symbol2'}
console.log(obj[a1]) // symbol1
console.log(obj[a2]) // symbol2

可以看到虽然value值都是a,但是生成的key都是不同的,不会被覆盖。

但是如果换成字符串,key是会被覆盖的。

let obj = {}
let a1 = 'a'
let a2 = 'a'
obj[a1] = 'a1'
obj[a2] = 'a2'
console.log(obj) // {a: 'a2'}
console.log(obj[a1]) // a2
console.log(obj[a2]) // a2

但是symbol生成的key,是不会被Object.keys,for-in等循环遍历出来的。

如果要遍历出来,可以使用Object.getOwnPropertySymbols方法遍历symbol的key值(它是专门遍历symbol的key值,其它普通值无法遍历)

Reflect.ownKeys可以遍历所有key值。

let obj = {}
let a = Symbol('a')
obj[a] = 'a'
console.log(obj) // {a: 'a', Symbol(a): 'a'}
console.log(Object.keys(obj)) // ['a']
console.log(Object.getOwnPropertySymbols(obj)) // [Symbol(a)]
console.log(Reflect.ownKeys(obj)) ['a', Symbol(a)]

因为它作为key值无法被Object.keys,for-in遍历到,所以可以使用它模拟使用私有属性。

3.既然Symbol代表的是独一无二的值,但是有时候我们想复用同一个Symbol。这时候可以使用Symbol.for方法。

let a1 = Symbol.for('a')
let a2 = Symbol.for('a')
console.log(a1 === a2) // true

Symbol.for方法会在全局寻找,如果有同样value的symbol,则返回该symbol,否则会创建新的symbol。

针对Symbol.for方法生成的symbol,Symbol.keyFor方法返回它的value。

let a1 = Symbol.for('a')
console.log(Symbol.keyFor(a1)) // a

4.Symbol.iterator属性

这个属性指向具有Iterator接口的数据的遍历方法,你进行for-of遍历的时候,如果数据有Symbol.iterator属性就可以遍历它。

因为对象没有Symbol.iterator属性,它无法进行for-of循环遍历。我们可以给它加上,让它可以遍历。需要提供next方法,返回 {value: xxx, done:xxx}

var obj ={key: 'a'}
for(let value of obj) {} // error: obj is not iterable

var obj = {
  index: 0,
  [Symbol.iterator]: function () {
    let next = () => {
        const index = this.index++
        return { value: index, done: index > 0 }
    }
    return { next }
  }
}
for(let value of obj) {console.log(value)} // 0

参考

Symbol