ECMA-262-v6 中的“符号”类型有啥意义?

Posted

技术标签:

【中文标题】ECMA-262-v6 中的“符号”类型有啥意义?【英文标题】:What is the point of the 'Symbol' type in ECMA-262-v6?ECMA-262-v6 中的“符号”类型有什么意义? 【发布时间】:2015-09-04 07:36:15 【问题描述】:

ECMA-262-v6 中“符号”类型的意义何在?对象键的快速路径实现?它在幕后做了什么 - 在保证底层数据不可变的情况下对其进行哈希处理?

【问题讨论】:

hacks.mozilla.org/2015/06/es6-in-depth-symbols 另见可能重复的Why bring symbols to javascript? 相关帖子 - What are the possible usage scenarios for the new JavaScript “Symbol” datatype? What is the motivation for bringing Symbols to ES6?的可能重复 【参考方案1】:

它们几乎可以帮助我们解决命名冲突。每当您想以独特的方式创建属性时,就应该使用符号。

看看我的例子

const bert = Symbol('Bert');

'伯特'

注意:这不是一个值,这是他们所谓的描述符, 因为符号本身只是一个唯一标识符。所以如果你是 想象一个符号可能是什么,也许你可以想象是 像这样的“sdfasdfa2342134987fgsdfgsdf9808fsfgsd”绝对 唯一的符号,这样您就可以确保它永远不会覆盖 那里的任何其他代码。

这很酷的是,如果我创建第二个符号,例如

const person = Symbol('Bert')

你可以看到我再次使用了“Bert”。因为我将它们描述为相同的东西,所以它们会相同吗?

const bert = Symbol('Bert');
const person = Symbol('Bert');


console.log(bert);
console.log(person);
console.log(bert === person);
console.log(bert == person);

如果您正在创建类的对象,这可能很有用。

  const classRoom = 
    'Mia' :  grade: 50, gender: 'female' ,
    'Gilbert':  grade: 80, gender: 'male' ,
    'Gilbert'  grade: 80, gender: 'male' ,
  ;

但是你有另一个名字叫 Gilbert,所以你有一个命名冲突。所以想象一下,如果你正在处理数以百万计的数据。因此,我们可以使用符号来命名,而不是使用人名或使用某种唯一标识符。

  const classRoom = 
    [Symbol('Mia')] :  grade: 50, gender: 'female' ,
    [Symbol('Gilbert')]:  grade: 80, gender: 'male' ,
    [Symbol('Gilbert')]:  grade: 80, gender: 'male' ,
  ;

关于符号的另一件事是它们不可枚举,这意味着如果我要这样做,我们就无法循环它们

  for (const person in classRoom) 
    console.log(person);
  

我什么也得不到。

如果您确实想要访问所有符号,因为它们是您想要获取的一些信息,您可以使用对象方法。

  const syms = Object.getOwnPropertySymbols(classRoom);
  const data = syms.map(sym => classRoom[sym]);
  console.log(data);

【讨论】:

只是想澄清一下,如果存在两个带有键 Symbol('Gilbert'] 的对象属性,我们如何读取特定的属性?【参考方案2】:

符号是替代魔术名称的私钥。它们阻止使用简单的字符串来引用该字段,因此只有具有该符号的消费者才能获得访问权限。

一些符号用于向运行时指示特定行为(如Symbol.iterator,其作用很像预先共享的秘密),而其他符号可以由库分配并用于有效隐藏字段。

一般来说,符号旨在替代魔法名称。您可以分配一个符号 const foo = Symbol() 并有选择地传递它,而不是简单地称为 'foo' 的属性。这允许运行时在启动时分配Symbol.iterator,并保证尝试实现可迭代的任何人都以一致的方式这样做。

运行时可以使用符号来优化对某些字段的访问,如果它觉得有必要,但不是必须的。

您可以使用符号将消费者引导至特定方法,具体取决于它们的用法。例如,如果您有一个可以返回同步迭代或生成器的库,取决于客户端的异步支持,您可以:

const syncIterable = Symbol();
const asyncIterable = Symbol();

class Foo 
  static getIterable(async = false) 
    return async ? asyncIterable : syncIterable;
  

  [syncIterable]() 
    return new SyncFoo();
  

  [asyncIterable]() 
    return new AsyncFoo();
  


let foo = new Foo();
for (let x of foo[Foo.getIterable(true)]()) 
  // could be a iterator, could be a generator

这是一个相当人为的示例,但显示了库如何使用符号有选择地为用户提供访问权限。

【讨论】:

“符号是替代魔法名称的私钥。” 不,符号根本不是私有的。一点儿都没有。 "...所以只有拥有该符号的消费者才能获得访问权限" 但是任何人都可以获得该符号,所以这没有任何意义:tc39.github.io/ecma262/#sec-object.getownpropertysymbols

以上是关于ECMA-262-v6 中的“符号”类型有啥意义?的主要内容,如果未能解决你的问题,请参考以下文章

foreach 中的泛型类型有啥意义?

Python中的“ @”(@)符号有啥作用?

类的 in 修饰符有啥意义

CAGradientLayer 类型——有啥意义?

左斜杠和右斜杠分别有啥意义?

在 Go 中使用指针有啥意义?