面试题:Javascript中Symbol有什么用处?

487 阅读2分钟

「这是我参与2022首次更文挑战的第12天,活动详情查看:2022首次更文挑战」。

基本概念

  • ES6中引入了一种新的原始数据类型symbol
  • 在MDN中这样描述

symbol 是一种基本数据类型 (primitive data type)。Symbol()函数会返回symbol类型的值,该类型具有静态属性和静态方法。它的静态属性会暴露几个内建的成员对象;它的静态方法会暴露全局的symbol注册,且类似于内建对象类,但作为构造函数来说它并不完整,因为它不支持语法:"new Symbol()"。

每个从Symbol()返回的symbol值都是唯一的。一个symbol值能作为对象属性的标识符;这是该数据类型仅有的目的。

基本使用

let apple = Symbol()
let banana = Symbol()

typeof apple // 'symbol'
apple == banana // false
apple === banana // false
  • 任意两个symbol都不相等

Symbol.for(key)

使用给定的key搜索现有的symbol,如果找到则返回该symbol。否则将使用给定的key在全局symbol注册表中创建一个新的symbol

let uid1 = Symbol.for('uid')
let uid2 = Symbol.for('uid')

uid1 // 'Symbol(uid)'
uid2 // 'Symbol(uid)'
uid1 === uid2 // true

Symbol.keyFor(sym)

从全局symbol注册表中,为给定的symbol检索一个共享的symbol key

let uid = Symbol.for('uid')

Symbol.keyFor(uid) // 'uid'

使用场景

定义私有变量

  • symbol可以很方便的模仿私有属性,Object.keys() 不会拿到用symbol类型的属性,除非使用 Object.getOwnPropertySymbols(),并且只有用这个symbol的引用才能访问该属性的值
let obj = {
    public: 'i am public'
}
const private = Symbol('private')
obj[private] = 'i am private'

Object.keys(obj) // ['public']
Object.getOwnPropertySymbols(obj) // [Symbol(private)]
obj[Symbol('private')] // undefined
obj[private] // 'i am private'

消除魔术字符串

  • 实际开发中,随着业务逐渐复杂,可能会产生与业务无关的且重复的魔法字符,这不利于日后业务的修改和维护
function doSomething(type) {
    switch(type) {
        case 'type1':
            'do case1'
            break
        case 'type2':
            'do case2'
            break
        case 'type3':
            'do case3'
            break
        default:
            'do default'
            break
    }
}

doSomething('type1')
  • 由于任意两个用Symbol()定义的变量都是不相等的,因此可以不用关心字符串本身
let obj = {
    type1: Symbol(),
    type2: Symbol(),
    type3: Symbol(),
}

function doSomething(type) {
    switch(type) {
        case obj.type1:
            'do case1'
            break
        case obj.type2:
            'do case2'
            break
        case obj.type3:
            'do case3'
            break
        default:
            'do default'
            break
    }
}

doSomething(obj.type1)