符号

浏览器支持

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

来源

符号原始值表示一个唯一值,该值永远不会与其他任何值冲突,包括其他符号原始值的值。由相同字符组成的两个字符串原始值求值结果为严格相等

String() === String()
> true

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

但是,使用 Symbol() 函数创建的任何两个符号永远不可能严格相等

Symbol() === Symbol()
> false

此特性使您可以在对象中使用符号作为唯一属性键,从而防止与任何其他代码可能添加到该对象的键发生冲突。

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 内置方法的唯一属性键