符号

Browser Support

  • Chrome: 38.
  • Edge: 12.
  • Firefox: 36.
  • Safari: 9.

Source

符号基元表示一个永远不会与任何其他值(包括其他符号基元的值)冲突的唯一值。由相同字符组成的两个字符串基元会被评估为完全相等:

String() === String()
> true

String( "My string." ) === String( "My string." );
> true

不过,使用 Symbol() 函数创建的任何两个符号都不可能完全相同:

Symbol() === Symbol()
> false

借助此 trait,您可以将符号用作对象中的唯一属性键,从而避免与任何其他代码可能向该对象添加的键发生冲突。

const mySymbol = Symbol( "Desc" );

const myObject = {};
myObject[mySymbol] = "propSymbol";

myObject
> Object { Symbol("Desc"): "propSymbol" }

符号分为三种类型:

  • 使用 Symbol() 创建的符号
  • 使用 Symbol.for() 从全局符号注册表设置和检索的共享符号
  • “众所周知的符号”定义为 Symbol 对象上的静态属性。这些符号包含无法意外覆盖的内部方法。

Symbol() 接受说明(或“符号名称”)作为可选实参。这些说明是供调试目的使用的人类可读标签,不会影响结果的唯一性。对 Symbol 的任何调用都会返回完全唯一的符号基元,即使多个调用的说明相同也是如此:

Symbol( "My symbol." ) === Symbol( "My symbol." );
> false

与其他基元数据类型一样,符号会从其原型继承方法和属性。例如,您可以将说明作为创建的符号的继承属性进行访问:

let mySymbol = Symbol( "My symbol." );

mySymbol.description
> "My symbol."

但您无法使用 new 关键字创建符号:

let mySymbol = new Symbol();

> Uncaught TypeError: Symbol is not a constructor

符号不可枚举,这意味着使用标准方法对符号进行迭代时,符号属性不可用。getOwnPropertySymbols() 方法可访问对象的符号属性。

共享符号

Symbol.for() 方法会尝试使用给定字符串作为键在运行时级全局符号注册表中查找任何现有符号,并在找到匹配符号时返回该符号。如果未找到,则会使用指定的键创建符号并将其添加到全局注册表中:

let sharedSymbol = Symbol.for( "My key." );

sharedSymbol === Symbol.for( "My key." )
> true

这些键与分配给作者创建的 Symbol 基元描述没有功能重叠。如需访问符号注册表中的符号,您必须先使用 for() 创建该符号:

Symbol( "String" ) === Symbol( "String" );
> false

Symbol( "String" ) === Symbol.for( "String" );
> false

Symbol.for( "String" ) === Symbol.for( "String" );
> true

如需从符号注册表中检索任何符号的键,请使用 Symbol.keyFor()

let mySymbol = Symbol.for( "Key." );

Symbol.keyFor( mySymbol ) ;
> "Key."

“众所周知”符号

众所周知的符号Symbol 对象的静态属性,每个属性本身就是一个符号。知名符号提供唯一的属性键,用于访问和修改 JavaScript 的内置方法,同时防止核心行为被无意中覆盖。

Symbol;
> function Symbol()
    asyncIterator: Symbol(Symbol.asyncIterator)
    for: function for()
    hasInstance: Symbol("Symbol.hasInstance")
    isConcatSpreadable: Symbol("Symbol.isConcatSpreadable")
    iterator: Symbol(Symbol.iterator)
    keyFor: function keyFor()
    length: 0
    match: Symbol("Symbol.match")
    matchAll: Symbol("Symbol.matchAll")
    name: "Symbol"
    prototype: Object {  }
    replace: Symbol("Symbol.replace")
    search: Symbol("Symbol.search")
    species: Symbol("Symbol.species")
    split: Symbol("Symbol.split")
    toPrimitive: Symbol("Symbol.toPrimitive")
    toStringTag: Symbol("Symbol.toStringTag")
    unscopables: Symbol("Symbol.unscopables")
    <prototype>: function ()

由于符号是 ES6 特有的功能,因此这些符号值旨在用作“扩展点”,供开发者修改 JavaScript 的行为,而不会引入向后兼容性问题。

众所周知的符号值通常带有 @@ 前缀或封装在 % 中,以便将其键与可变原型区分开来。例如,@@match(或 %match%)是对不可变 Symbol.match 的引用,而不是对 String.prototype.match 的引用。

检查您的理解情况

您可以使用 new 创建符号吗?

以下哪些描述了“众所周知”的符号?

`Symbol` 对象的静态属性
您经常使用的符号
用于访问和修改 JavaScript 内置方法的唯一属性键