访问ES6中的[[NativeBrand]]/[[Class]](ECMAScript 6)

Nat*_*all 7 javascript ecmascript-harmony

我正在阅读ES6的草案,我注意到以下Object.prototype.toString部分中的这个注释:

从历史上看,此函数偶尔用于访问本规范以前版本中使用的[[Class]]内部属性的字符串值,作为各种内置对象的名义类型标记.toString的这个定义保留了将它用作那些特定类型的内置对象的可靠测试的能力,但它没有为其他类型的内置或程序定义的对象提供可靠的类型测试机制.

通过在es-discuss上阅读这个帖子,听起来好像在ES6草案中[[Class]]被替换,[[NativeBrand]]以便他们可以将其指定为不可扩展(那些至少是Allen Wirfs-Brock的想法).

好奇,我在FireFox和Chrome上进行了快速测试(启用了实验性JavaScript):

Object.prototype.toString.apply(new WeakMap());
=> '[object WeakMap]'
Run Code Online (Sandbox Code Playgroud)

"WeakMap"不是[[NativeBrand]]ES6草案中规定的内容之一.但是,这"[object WeakMap]"两个浏览器都返回了此测试.

所以我很困惑.我有几个问题.


1. Chrome和Firefox的行为是否正确?

从阅读草案的一种方式来看,它听起来应该回归[object Object](而且所有这些都是新的,所以在这些浏览器的未来版本中看到这种变化我不会感到惊讶).但是,我很难理解草案本节的意图,特别是因为有一些地方"???".

是否有人更热切地关注es-discuss有任何相关信息?或者任何能够更好地理解草案语言的人?


2.有替代方案Object.prototype.toString吗?

从上面引用的说明中,它听起来好像Object.prototype.toString是为了遗留原因而保留,好像现在应该使用新的东西.特别是读取节点的一部分"it does not provide a reliable type testing mechanism for other kinds of built-in ... objects".这是否意味着未来的内置插件无法使用此方法进行测试?

让我们用一个具体的例子.

如果我想确保我从未知来源收到的String对象是一个对象(一个实际构造的String对象,而不是一个原始字符串),我可以这样做:

if (Object.prototype.toString.apply(unknownObject) != '[object String]')
    throw new TypeError('String object expected.');
Run Code Online (Sandbox Code Playgroud)

这让我知道是否unknownObject是一个String对象,无论它构造在什么框架中.

我的问题是,这应该是我采用ES6的方法吗?还是有替代方案吗?有点像Object.getNativeBrandOf


3.由于[[NativeBrand]]它似乎不包括未来的对象类型,如何测试这些对象?

这会有用吗?

if (Object.prototype.toString.apply(unknownObject) != '[object Symbol]')
    throw new TypeError('Symbol expected.');
Run Code Online (Sandbox Code Playgroud)

...假设Symbol是私人名称的最终名称.

我应该用这个吗?

if (Object.prototype.toString.apply(unknownObject) != '[object WeakMap]')
    throw new TypeError('WeakMap expected.');
Run Code Online (Sandbox Code Playgroud)

... 或者是其他东西?


我问的原因是我目前正在编写代码,我希望能够在一年或两年内尽可能轻松地转换到ES6.如果有更换Object.prototype.toString,那么我可以将其填入并从那里继续.谢谢!


更新

benvie的回答为我提供了正确的术语来搜索和理解我的问题的答案.

我发现了Allen Wirfs-Brock关于这个问题的es-discuss的电子邮件.

这是我发现的,对于其他人提出同样的问题:

1. Chrome和Firefox的行为是否正确?

是的,为什么在下面解释.

2.有替代方案Object.prototype.toString吗?

就像现在一样,在可能性的意义上会有一些"替代品" ,但在替代品意义上却没有.

一个. 使用@@toStringTag符号.但是,我的理解是Object.prototype.toString应该仍然可以使用.@@toStringTag用于扩展可以返回的结果Object.prototype.toString.如果你有一个原型,你想添加自己的字符串标记,你可以@@toStringTag用来设置任何字符串的值.Object.prototype.toString将返回此值,除非此值是ES5内置函数之一,在这种情况下,字符串标记将以"〜"前缀.

在用户定义的对象上使用私有符号.我读了一封电子邮件,宣传这是对用户定义的对象进行相同类型检查的最佳方式.但是,我不知道这是如何真正解决问题的,因为我无法理解它是如何成为跨框架解决方案而且它不会让你检查ES6内置插件.

因此,尽管有一些替代方案,但Object.prototype.toString现在坚持下去并继续前进是一件好事,只需注意一点:

它可以确保你有一个内置的ES5 String,但是确保你有一个内置的ES6并不是万无一失的,因为它们可以被欺骗@@toStringTag.我不确定为什么会这样,我可能会遗漏一些东西,或者随着规范的发展它可能会改变.

3.由于[[NativeBrand]]它似乎不包括未来的对象类型,如何测试这些对象?

如上所述,Object.prototype.toString仍然可以在ES6内置插件上使用,但它不是万无一失的,因为任何有权访问该@@toStringTag符号的人都可以欺骗它.但是,也许不应该有一个万无一失的方法,因为Object.prototype.toString(weakmap) == '[object WeakMap]'并不意味着weakmap instanceof WeakMap(它不应该!).的weakmap可能来自另一帧,或者它可以是用户创建的weakmap状物体.你真正知道的唯一一件事是它报告功能上等同于WeakMap.

它似乎提出了一个问题,为什么你不能拥有一个用户定义的对象,该对象报告在功能上等同于a StringArray(没有前缀"~").

小智 1

目前,这是 ES6 规范中的一个移动目标。对于现有的一组对象,由于各种原因(包括兼容性)而维持现有的机制。在10 月 26 日发布的最新 ES6 规范中,您可以找到一些未来潜在方向的提示

15.4.6.2.4 ArrayIterator.prototype.@@toStringTag
@@toStringTag 属性的初始值为字符串值“Array Iterator”。

15.14.5.13 Map.prototype.@@toStringTag
@@toStringTag 属性的初始值为字符串值“Map”。

您可以在es-discuss 上的这个线程中找到引发此问题的原始讨论