首页 > 编程笔记 > JavaScript笔记 阅读:15

JavaScript Symbol类型的用法(附带实例)

ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值。它属于 JavaScript 语言的原生数据类型之一。

Symbol 值通过 Symbol() 函数生成:
let s1 = Symbol(); // 变量s1是一个独一无二的值
let s2 = Symbol(); // 变量s2是一个独一无二的值
console.log(s1 === s2) // false

Symbol() 函数可以接收一个字符串作为参数,表示对 Symbol 实例的描述,主要是为了在控制台显示,或者在转换为字符串时比较容易区分。相同参数的 Symbol() 函数的返回值是不相等的。
let s1 = Symbol('foo'); // 变量s1是一个独一无二的值
let s2 = Symbol('bar'); // 变量s2是一个独一无二的值
console.log(s1) // Symbol(foo)
console.log(s2) // Symbol(bar)
console.log(Symbol('foo') === Symbol('foo')) // false

ES6 之前的对象属性名都是字符串,这容易造成属性名的冲突。比如使用一个第三方提供的对象,但又想对这个对象添加新的方法,新方法的名字就有可能与现有方法产生冲突。

数据类型 Symbol 可以从根本上防止属性名的冲突。这也是 ES6 设计出 Symbol 的初衷:解决对象的属性名冲突。
let mySymbol = Symbol(); // 变量mySymbol是一个独一无二的值
let a = {};
a[mySymbol] = 'Hello!';
console.log(a[mySymbol]); // "Hello!"

Symbol 值作为对象属性名时,不能用点运算符:
const mySymbol = Symbol();
const a = {};
a.mySymbol = 'Hello!';
a['mySymbol'] // undefined
a[mySymbol] // "Hello!"
在上面代码中,因为点运算符后面总是字符串,所以不会读取 mySymbol 作为标识名所指代的那个值,导致 a 的属性名实际上是一个字符串,而不是一个 Symbol 值。

同理,在对象的内部,使用 Symbol 值定义属性时,Symbol 值必须放在方括号之中。
let mySymbol = Symbol();
let a = {
    [mySymbol]: 'Hello!'
};
在上面代码中,如果 mySymbol 不放在方括号中,则该属性的键名就是字符串 mySymbol,而不是 mySymbol 所代表的那个 Symbol 值。

【实例】消除魔术字符串。魔术字符串指的是,在代码之中多次出现、与代码形成强耦合的某一个具体的字符串或者数值。风格良好的代码应该尽量消除魔术字符串,改由含义清晰的变量代替。
function isMan(gender) {
    switch (gender) {
        case 'man':
            console.log('男性');
            break;
        case 'woman':
            console.log('女性');
            break
    }
}
isMan('man') // 男性
在上面代码中,字符串 man 就是一个魔术字符串,它与代码形成“强耦合”,不利于将来的修改和维护。

常用的消除魔术字符串的方法就是把它写成一个变量:
const gender = {
    man: 'man',
    woman: 'woman',
}
在上面代码中,把字符串 man 写成 gender 对象的 man 属性,这样就消除了强耦合。更进一步,可以发现 gender.man 等于哪个值并不重要,只要确保不会跟其他 gender 属性的值冲突即可。因此,这里就很适合改用 Symbol 值。
const gender = {
    man: Symbol(),
    woman: Symbol()
}
在上面代码中,除了将 gender.man 和 gender.woman 的值设为一个 Symbol 之外,其他地方都不用修改。

相关文章