ES6中的新數據類型——Symbol

今天小編和大家來聊一聊es6中新增的一個原始數據類型Symbol。在es5中原始數據類型(基本數據類型)有以下六種:Undefind、Null、Bool、 String、Number、Object。今天結合實例和大家一起探討一下這個神奇的Symbol。大家也可以關注我的微信公眾號,蝸牛全棧。

一、基本聲明方式
1、方式一

 let s1 = Symbol()
 let s2 = Symbol()
 console.log(s1) // Symbol{}
 console.log(s2) // Symbol{}
 console.log(s1 === s2) // false 說明每一個Symbol用這種方式聲明都是與眾不同的。後續會有應用

2、方式二

let s1 = Symbol('foo')
let s2 = Symbol('bar')

console.log(s1) // Symbol(foo)
console.log(s2) // Symbol(bar)
console.log(s1 === s2) // false
const obj = {
    name:"lilei",
    toString(){
        return this.name
    }
}
let s = Symbol(obj) // 如果參數是Object的時候,會自動調用該對象的toString方法
console.log(s) // Symbol(lilei)

3、關於description

let s = Symbol()
s.name = "lilei"
console.log(s) // Symbol{} // Symbol不是對象,不能用對待對象的方式對待Symbol
console.log(s.description) // undefind
console.log(s.name) // undefind
let s = Symbol('foo')
console.log(s.description) // foo

二、Symbol.for:通過Symbol.for相當於定義在全局的變數,如果之前聲明過,後面再通過Symbol.for的時候,會在全局找,如果描述一樣的話,會和上一個一樣。可以簡單理解為對象指向同一個堆記憶體地址。

let s1 = Symbol.for('foo')
let s2 = Symbol.for('foo')
console.log(s1) // Symbol(foo)
console.log(s1 === s2) // true
// 即使是在函數定義域內,通過Symbol.for也會將該Symbol註冊在全局
function foo(){
    return Symbol.for('foo')
}

const x = foo()
const y = Symbol.for('foo')
console.log(x === y) // true

三、Symbol.keyFor:查看是否在全局登記Symbol裡面的描述。與上面的Symbol.for對應。

const s1 = Symbol('foo')
console.log(Symbol.keyFor(s1)) // undefind
const s2 = Symbol.for('foo')
console.log(Symbol.keyFor(s1)) // foo

四、實際應用:
應用一:解決對象中key重複但是表示不同資訊的情況

// 對象對於相同的key的資訊會進行覆蓋
const grade = {
    zhangsan:{
        address:"xxx",tel:"111"
    },
    lisi:{
        address:"yyy",tel:"222"
    },
    lisi:{
        address:"zzz",tel:"333"
    },
}

console.log(grade) // {zhangsan:{address:"xxx",tel:"111"},lisi:{address:"zzz",tel:"333"}}
// 通過變數構建對象
const stu1 = "lisi"
const stu2 = "lisi"
const grade = {
    [stu1]:{
        address:"yyy",tel:"222"
    },
    [stu2]:{
        address:"zzz",tel:"333"
    },
}
console.log(grade) // {lisi:{address:"zzz",tel:"333"}}
// es6通過Symbol解決key相同,資訊不同情況
const stu1 = Symbol("lisi")
const stu2 = Symbol("lisi")
const grade = {
    [stu1]:{
        address:"yyy",tel:"222"
    },
    [stu2]:{
        address:"zzz",tel:"333"
    },
}
console.log(grade) // {Symbol(lisi):{address:"yyy",tel:"222"},Symbol(lisi):{address:"zzz",tel:"333"}}
console.log(grade[stu1]) // {address:"yyy",tel:"222"}

應用二:保護類中的部分屬性

// 定義基本類和類中方法調用
class User{
    constructor(name){
        this.name = name
    }
    getName(){
        return this.name
    }
}

const user = new User("lilei")
console.log(user.getName()) // lilei
// 不同循環遍歷方式獲取類內部屬性,根據是否可以獲取Symbol作為key的情況
const sym = Symbol("AILI")
class User{
    constructor(name){
        this.name = name
        this[sym] = "AILI.com"
    }
    getName(){
        return this.name + this[sym]
    }
}

const user = new User("lilei")
console.log(user.getName()) // lileiAILI.co// 通過for...in 無法遍歷到Symbol屬性
for(let key in user){
    console.log(key) // name
}

// 同樣不能獲取到Symbol屬性
for(let key of Object.keys(user)){
    console.log(key) // name
}
// 只能取到Symbol屬性
for(let key of Object.getOwnPropertySymbols(user)){
    console.log(key) // Symbol(AILI)
}

// 即能獲取到普通屬性,又能獲取到Symbol屬性
for(let key of Reflect.ownKeys(user)){
    console.log(key) // name Symbol(AILI)
}

應用三:消除魔法字元串(比較長或者難以辨認,容易出錯的字元串)

// 函數實現基本功能,函數中【Triangle】和【Circle】比較容易出錯
function getArea(shape){
    let area = 0
    switch(shape){
        case "Triangle":
            area = 1
            break
        case "Circle":
            area = 2
            break
    }
    return area
}
console.log(getArea("Triangle")) // 1
// 通過對象,將魔法字元串初步隱藏
const shapeType = {
    triangle:"Triangle",
    circle:"Circle"
}
function getArea(shape){
    let area = 0
    switch(shape){
        case shapeType.triangle:
            area = 1
            break
        case shapeType.circle:
            area = 2
            break
    }
    return area
}
console.log(getArea(shapeType.triangle)) // 1
// 在這個函數中,【Triangle】和【Circle】已經不重要,只要區分開即可,利用Symbol不一致性
const shapeType = {
    triangle:Symbol(),
    circle:Symbol()
}
function getArea(shape){
    let area = 0
    switch(shape){
        case shapeType.triangle:
            area = 1
            break
        case shapeType.circle:
            area = 2
            break
    }
    return area
}
console.log(getArea(shapeType.triangle)) // 1