7.3 使用 Symbol 来表达一些概念
在 ECMAScript 5 中,一种常用的表达特殊含义(想想枚举常量)是通过字符串来实现的。例如:
var COLOR_RED = 'Red';
var COLOR_ORANGE = 'Orange';
var COLOR_YELLOW = 'Yellow';
var COLOR_GREEN = 'Green';
var COLOR_BLUE = 'Blue';
var COLOR_VIOLET = 'Violet';
然而,字符串并不是我们想象中的那么具有唯一性。为什么呢?请看如下函数。
function getComplement(color) {
switch (color) {
case COLOR_RED:
return COLOR_GREEN;
case COLOR_ORANGE:
return COLOR_BLUE;
case COLOR_YELLOW:
return COLOR_VIOLET;
case COLOR_GREEN:
return COLOR_RED;
case COLOR_BLUE:
return COLOR_ORANGE;
case COLOR_VIOLET:
return COLOR_YELLOW;
default:
throw new Exception('Unknown color: '+color);
}
}
很明显,你可以使用任何表达式作为 switch case
中的表达式,并不局限于某种形式。例如:
function isThree(x) {
switch (x) {
case 1 + 1 + 1:
return true;
default:
return false;
}
}
我们使用了 switch
提供的便利,用常量来指代颜色( COLOR_RED
等等),而不是使用硬编码的方式( 'RED
' 等)。
有趣的是,即便我们使用了常量,还是会产生混淆。例如,某个人可能随手定义一个常量:
var MOOD_BLUE = 'BLUE';
现在, BLUE
值再也不是唯一的了, MOOD_BLUE
与其冲突了。如果将它作为 getComplement()
的参数,原本期望能抛出异常,结果却返回了 'ORANGE'
。
让我们使用 symbol 来解决这个问题。现在,我们同样能够使用 ES6 的 const
特性,这样就可以声明真正的常量了(不能改变常量的指向,但是值本身可能是可变的)。
const COLOR_RED = Symbol('Red');
const COLOR_ORANGE = Symbol('Orange');
const COLOR_YELLOW = Symbol('Yellow');
const COLOR_GREEN = Symbol('Green');
const COLOR_BLUE = Symbol('Blue');
const COLOR_VIOLET = Symbol('Violet');
Symbol 返回的每一个值都是唯一的,这就是为什么没有其他的值可以和 BLUE
发生冲突的原因。有趣的是,如果我们使用 symbol 对象替换字符串,并不需要改动 getComplement()
函数,这表明两种方案的代码是多么的相似。