全局符号注册表和跨领域符号

时间:2019-05-21 21:50:19

标签: javascript

我试图了解Symbol()和Symbol.for()在跨领域方面的区别。

我已阅读这篇文章:http://2ality.com/2014/12/es6-symbols.html,据说:

  

符号具有各自的标识,因此跨域的传播不像其他原始值那样顺畅。对于像Symbol.iterator这样的符号来说,这应该在各个领域中都可以解决:如果一个对象在一个领域中是可迭代的,那么它在其他领域中也应该是可迭代的。如果JavaScript引擎提供了跨领域符号,则该引擎可以确保在每个领域中使用相同的值。但是,对于库,我们需要额外的支持,以全局符号注册表的形式出现:该注册表对所有领域都是全局的,并将字符串映射到符号。对于每个符号,库都需要提供一个尽可能唯一的字符串。要创建符号,他们不使用Symbol(),而是向注册表询问字符串所映射到的符号。如果注册表中已经有该字符串的条目,则返回关联的符号。否则,将首先创建条目和符号。

坦率地说,我不知道符号在一个领域中可访问而在另一个领域中不可访问意味着什么。我已经尝试了这段代码:

  <iframe srcdoc="<script>var sym = Symbol(); var obj = {}; obj[sym] = 123;</script>">
  </iframe>
  <script>
    const iframe = document.querySelector('iframe');
    const content = iframe.contentWindow;
    const value = content.obj[content.sym]
  </script>

当consol记录值时,在iframe以外的其他域中,我的值为123。sym是否不应该存在于我的脚本中?上面的代码难道不能证明符号确实跨领域传播吗?

1 个答案:

答案 0 :(得分:1)

这里的区别是当你这样做

const value = content.obj[content.sym]

您正在使用跨领域符号content.obj访问跨领域对象content.sym。父框架可以访问两个跨领域项目。问题在于“相同”符号不能用于访问不同领域中的属性。

如果子领域中的Symbol S用于访问子领域中的对象,并且该对象上带有S,则没有问题,如您的示例所示。问题是,当来自子领域的Symbol S用于访问“父领域”中的对象,并且该父领域对象还具有foo Symbol属性时,跨领域属性查找可能会失败:

<iframe srcdoc="<script>var sym = Symbol('foo');</script>">
  </iframe>
<script>
  const obj = {};
  const sym = Symbol('foo');
  obj[sym] = 'value';

  const iframe = document.querySelector('iframe');
  const content = iframe.contentWindow;
  const value = obj[content.sym];
  console.log(value); // undefined
</script>

https://jsfiddle.net/k4xh97ge/

结果:valueundefined,因为一个领域中foo的符号与另一领域中foo的符号不同。属性查询仅在以下情况下有效

(1)如本文所述,该符号来自全局符号注册表,或者

(2)父领域对象使用子领域中的符号(这是非常非常奇怪的事情),例如:

<iframe srcdoc="<script>var sym = Symbol('foo');</script>">
  </iframe>
<script>
  const obj = {};
  const crossRealmSymbol = document.querySelector('iframe').contentWindow.sym;
  obj[crossRealmSymbol] = 'value';
  console.log(obj[crossRealmSymbol]);
</script>

https://jsfiddle.net/k4xh97ge/1/

结果:value'value'