JavaScript 系列 - symbol

152 阅读2分钟

概念

  • symbol 是一种基本数据类型。类似于字符串的数据类型
  • Symbol()函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述
  • Symbol 值可以转为字符串和布尔值

注意

  • Symbol() 函数前不能使用 new 命令
  • 相同参数的 Symbol 函数的返回值是不相等的
  • Symbol 值不能与其他类型的值进行运算
  • Symbol 值不能转为数值
  • Symbol 值作为对象属性名时,不能用点运算符

使用

description

const sym = Symbol('foo');
sym.description // "foo"

作为属性名的 Symbol

Symbol 值作为属性名时,该属性还是公开属性,不是私有属性。

在对象的内部,使用 Symbol 值定义属性时,Symbol 值必须放在方括号之中

let mySymbol = Symbol();

// 第一种写法
let a = {};
a[mySymbol] = 'Hello!';

// 第二种写法
let a = {
  [mySymbol]: 'Hello!'
};

// 第三种写法
let a = {};
Object.defineProperty(a, mySymbol, { value: 'Hello!' });

// 以上写法都得到同样结果
a[mySymbol] // "Hello!"

属性名的遍历

Symbol 值作为属性名,遍历对象的时候,该属性不会出现在 for...infor...of 循环中,也不会被 Object.keys()Object.getOwnPropertyNames()JSON.stringify() 返回。

Object.getOwnPropertySymbols() 可以获取指定对象的所有 Symbol 属性名。该方法返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。 Reflect.ownKeys(obj)

const obj = {};
const foo = Symbol('foo');

obj[foo] = 'bar';

for (let i in obj) {
  console.log(i); // 无输出
}

Object.getOwnPropertyNames(obj) // []
Object.getOwnPropertySymbols(obj) // [Symbol(foo)]

为对象定义一些非私有的、但又希望只用于内部的方法。

Symbol.for() 和 Symbol.keyFor()

接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建一个以该字符串为名称的 Symbol 值,并将其注册到全局。

Symbol.keyFor() 方法返回一个已登记的 Symbol 类型值的 key

Symbol.for() 的这个全局登记特性,可以用在不同的 iframe 或 service worker 中取到同一个值。

const iframe = document.createElement('iframe');
iframe.src = String(window.location);
document.body.appendChild(iframe);
iframe.contentWindow.Symbol.for('foo') === Symbol.for('foo');

定义一组常量

const log = {};

log.levels = {
  DEBUG: Symbol('debug'),
  INFO: Symbol('info'),
  WARN: Symbol('warn')
};
console.log(log.levels.DEBUG, 'debug message');
console.log(log.levels.INFO, 'info message');
const COLOR_RED    = Symbol();
const COLOR_GREEN  = Symbol();

function getComplement(color) {
  switch (color) {
    case COLOR_RED:
      return COLOR_GREEN;
    case COLOR_GREEN:
      return COLOR_RED;
    default:
      throw new Error('Undefined color');
    }
}

消除魔术字符串

const shapeType = {
  triangle: Symbol()
};

function getArea(shape, options) {
  let area = 0;
  switch (shape) {
    case shapeType.triangle:
      area = .5 * options.width * options.height;
      break;
  }
  return area;
}

getArea(shapeType.triangle, { width: 100, height: 100 });

单例模式

// mod.js
const FOO_KEY = Symbol('foo');

function A() {
  this.foo = 'hello';
}

if (!global[FOO_KEY]) {
  global[FOO_KEY] = new A();
}

module.exports = global[FOO_KEY];

内置的 Symbol 值

Symbol.hasInstance、Symbol.isConcatSpreadable、Symbol.species、Symbol.match、Symbol.replace、Symbol.search、Symbol.split、Symbol.iterator、Symbol.toPrimitive、Symbol.toStringTag、Symbol.unscopables