Symbol 对象

发布日期:

Symbol是ES6中定义的一种独一无二的值,通过Symbol()函数生成。

let s = Symbol();
typeof s
// "symbol"

因为生成的 Symbol 是一个原始类型的值,不是对象,所以Symbol函数前不能使用new命令,否则会报错。也就是说,由于 Symbol 值不是对象,所以不能添加属性。基本上,它是一种类似于字符串的数据类型。
Symbol()函数可以接受一个字符串作为参数,但此参数仅作区分作用,并无其它意义。

let s1 = Symbol('foo');
let s2 = Symbol('bar');
s1 // Symbol(foo)
s2 // Symbol(bar)
s1.toString() // "Symbol(foo)"
s2.toString() // "Symbol(bar)"

所以即便是传入相同参数的Symbol()函数生成的值也并不会相同

// 没有参数的情况
let s1 = Symbol();
let s2 = Symbol();
s1 === s2 // false
// 有参数的情况
let s1 = Symbol('foo');
let s2 = Symbol('foo');
s1 === s2 // false

Symbol值可以转换为布尔值但不能转换为数值

let sym = Symbol();
Boolean(sym) // true
!sym  // false
if (sym) {
  // ...
}
Number(sym) // TypeError
sym + 2 // TypeError

魔术字符串

function getArea(shape, options) {
  let area = 0;
  switch (shape) {
    case 'Triangle': // 魔术字符串
      area = .5 * options.width * options.height;
      break;
    /* ... more code ... */
  }
  return area;
}
getArea('Triangle', { width: 100, height: 100 }); // 魔术字符串

上面的代码中,字符串Triangle为一个魔术字符串,与代码形成强耦合,为了维护,最好把他写成一个值而不是一个字符串,

const shapeType = {
  triangle: 'Triangle'
};
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 });

但是我们发现,shapeType.triangle值为多少并不重要,我们只要知道它表示要计算三角形面积即可,所以这时,它完全可以写成一个Symbol

const shapeType = {
  triangle: Symbol()
};

Object.getOwnPropertySymbols

Object.getOwnPropertySymbols方法返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。

const obj = {};
let a = Symbol('a');
let b = Symbol('b');
obj[a] = 'Hello';
obj[b] = 'World';
const objectSymbols = Object.getOwnPropertySymbols(obj);
objectSymbols
// [Symbol(a), Symbol(b)]

Reflect.ownKeys

Reflect.ownKeys方法可以返回所有类型的键名,包括常规键名和 Symbol 键名。

let obj = {
  [Symbol('my_key')]: 1,
  enum: 2,
  nonEnum: 3
};
Reflect.ownKeys(obj)
//  ["enum", "nonEnum", Symbol(my_key)]

Symbol.for()

Symbol.for接受一个字符串作为参数,他会去搜索有没有以这个参数作为参数的Symbol值。若有则返回这个值,若无则重新生成此值。

let s1 = Symbol.for('foo'); // 没有此值,生成
let s2 = Symbol.for('foo'); // 发现上行代码生成的值
s1 === s2 // true

参考

《ES6标准入门》