Symbol类型

133 阅读2分钟

前言

Symbol 会生成唯一值,防止属性名出现冲突而产生的,因此在一些自定义组件或三方库中比较容易见到,平时一般也不常用,封装一些特殊组件,也许能有所帮助

Symbol 介绍

Symbol

使用 Symbol 每次创建的值都不一样(使用时,可以把这个对象理解为对象指针作为key,每次创建一定不一样)

const sym = Symbol()
const sym2 = Symbol()
console.log(sym === sym2) //false

Symbol 支持携带描述参数,仅仅是描述参数,不影响其值不一样,通过 description 属性可以获取描述参数

const sym = Symbol('name')
const sym2 = Symbol('name')
console.log(sym === sym2) //false

console.log(sym.description) //name

Symbol.for

Symbol.for() 支持根据描述登记,未登记生成新的,已登记返回登记过的 Symbol,可以理解为加入缓存

const sym = Symbol.for('name');
const sym2 = Symbol.for('name');
console.log(sym === sym2) //true

基础使用案例

如何声明一个 Symbol 属性名,需要注意的是,属性名类型只有 string、symbol,可以说比较固定了,symbol 一个特殊定义的其他类型属性(有点像其他语言中的指针所谓哈希值了🤣)

const symbol = Symbol()
const obj = {
    [symbol]: '啦啦啦'
}
console.log(obj[symbol])

遍历

会发现正常遍历无法遍历

const symbol = Symbol();
const obj = {
    [symbol]: "啦啦啦",
    name: '帅呆了'
};

Object.keys(obj).forEach((item) => {
	console.log(item)
})

无法正常遍历不代表无法遍历,可以通过 Object.getOwnPropertySymbols、Reflect.ownKeys 方法获取到

Object.getOwnPropertySymbols 专门获取 Symbol 类型的 key

Reflect.ownKeys 后者是通过反射获取所有的 key

实际应用

为了保护一些参数不被正常遍历到,可以通过设置 Symbol 的方式来存取内容

const special = Symbol();
class User {
    constructor(name, idcard) {
        this[special] = idcard;
        this.name = name;
    }
    getIdCard() {
        return this[special];
    }
}

//外部使用
const user = new User('帅', '111111')
console.log(user.getIdCard())

也可以这么改动,根据自己情况选择使用即可

class User {
    constructor(name, idcard) {
        this[Symbol.for('user_idcard')] = idcard;
        this.name = name;
    }
    getIdCard() {
        return this[Symbol.for("user_idcard")];
    }
}

//外部使用
const user = new User('帅', '111111')
console.log(user.getIdCard())

扩展

通过 # 修饰的属性名,为私有属性,不能被外部访问到(ts 中的一些标记手段仅仅是ts类型报错,就和早期 _ 开头的标记私有属性一样,有风险,都可以被访问到,只不过多了个ts报错),这个是确实存在的私有属性,如下所示

class Obj {
	#name;
	lala = '啦啦';

    constructor(name) {
        // 私有函数
        this.#name = name;
    }

    getName() {
        return this.#name;
    }
};

const obj = new Obj('名字')

Reflect.ownKeys(obj).forEach((item) => {
  console.log(item);
}); //lala

console.log(obj.getName()) //名字