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() 函数,这表明两种方案的代码是多么的相似。

results matching ""

    No results matching ""