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

查看:92
本文介绍了访问ES6中的[[NativeBrand]] / [[Class]](ECMAScript 6)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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


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


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



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

  Object.prototype.toString。 apply(new WeakMap()); 
=> '[object WeakMap]'

WeakMap不是ES6草案中指定的 [[NativeBrand]] 之一。但是,这个测试在两个浏览器上都返回[object WeakMap]



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






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



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



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






2。是否有替代 Object.prototype.toString



从上面引用的注释中可以看出听起来好像 Object.prototype.toString 由于遗留原因而被保留,好像现在应该使用新的东西。特别是节点的一部分读取它没有为其他类型的内置...对象提供可靠的类型测试机制。这是否意味着未来的内置插件无法使用此方法进行测试?



让我们使用一个具体的例子。



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

  if(Object.prototype.toString.apply(unknownObject) !='[object String]')
抛出新的TypeError('String object expected。');

这让我知道 unknownObject 是否是 String 对象,无论它构造在什么框架内。



我的问题是,这应该是我采取的方法吗?进入ES6?还是有替代方案吗?类似 Object.getNativeBrandOf






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



这会有效吗?

  if(Object.prototype.toString.apply(unknownObject)!= '[object Symbol]')
抛出新的TypeError('符号期望。');

...假设符号是最终的私人姓名的名称。



我应该使用这个吗?

  if (Object.prototype.toString.apply(unknownObject)!='[object WeakMap]')
抛出新的TypeError('WeakMap expected。');

......还是别的什么?






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






更新



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



我发现来自Allen Wirfs-Brock的关于此问题的电子讨论的电子邮件。



以下是我发现的内容,对于其他提出相同问题的人:



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



是,为什么在下面说明。



2。是否有替代 Object.prototype.toString



现在,将会在可能性的意义上是一对替代品,但不是替换意义上的。



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



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



所以,即使有一些替代方案,现在坚持使用 Object.prototype.toString 并继续前进,只需注意一点:



它可以确保你有一个内置的ES5,例如 String ,但它不会为了确保你有一个ES6内置,因为它们可以用 @@ toStringTag 进行欺骗,所以万无一失。我不确定为什么会这样,我可能会遗漏某些东西,或者随着规格的发展而改变。



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



如上所述, Object.prototype.toString 仍然可以用在ES6内置插件上,但它不是万无一失的,因为它可以是任何有权访问 @@ toStringTag 符号的人都会欺骗。但是,也许不应该有傻瓜式方法,因为 Object.prototype.toString(weakmap)=='[object WeakMap]'并不意味着弱地图实例WeakMap (它不应该!)。 weakmap 可能来自另一个框架,或者它可能是用户创建的类似弱图的对象。你真正知道的唯一的事情是它报告功能上等同于WeakMap。



它似乎提出了一个问题,为什么你不能有一个用户定义的对象报告在功能上等同于字符串数组(没有前缀)。

解决方案

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


15.4.6.2.4 ArrayIterator.prototype。@@ toStringTag

@@ toStringTag属性的初始值是
字符串值Array Iterator。



15.14.5.13 Map.prototype。@@ toStringTag

@@ toStringTag属性的初始值是字符串值Map。


你可以找到原来的讨论在es-discuss上发起了这个在这个主题中


I was reading over the draft for ES6, and I noticed this note in the Object.prototype.toString section:

Historically, this function was occasionally used to access the string value of the [[Class]] internal property that was used in previous editions of this specification as a nominal type tag for various built-in objects. This definition of toString preserves the ability to use it as a reliable test for those specific kinds of built-in objects but it does not provide a reliable type testing mechanism for other kinds of built-in or program defined objects.

From reading this thread on es-discuss, it sounds like [[Class]] is being replaced with [[NativeBrand]] in the ES6 draft so that they can specify it as being non-extensible (those were at least Allen Wirfs-Brock's thoughts).

Curious, I ran a quick test in FireFox and Chrome (with experimental JavaScript enabled):

Object.prototype.toString.apply(new WeakMap());
=> '[object WeakMap]'

"WeakMap" is not one of the [[NativeBrand]]s specified in the ES6 draft. However, this test returned "[object WeakMap]" on both browsers.

So I'm confused. I have a few questions.


1. Do Chrome and Firefox behave correctly?

From one way of reading the draft it sounds like they should return [object Object] (and all of this is pretty new, so I wouldn't be surprised to see this change in future editions of these browsers). However, it's hard for me to understand the intention of this section of the draft, especially since there are some places with "???".

Does anyone who has been following es-discuss more fervently have any relevant information? Or anyone who can understand the draft language better?


2. Is there an alternative to Object.prototype.toString?

From the note quoted above it makes it sound as if Object.prototype.toString is retained for legacy reasons, as if there's something new now that should be used instead. Especially the part of the node that reads "it does not provide a reliable type testing mechanism for other kinds of built-in ... objects". Does that mean that future built-ins can't be tested with this method?

Let's use a concrete example.

If I want to ensure an object I have received from an unknown source is a String object (an actual constructed String object, not a primitive string), I could do:

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

This lets me know if unknownObject is a String object no matter what frame it was constructed in.

My question is, should this be the approach I take moving forward into ES6? Or is there an alternative? Something like Object.getNativeBrandOf?


3. Since [[NativeBrand]] seems like it won't include future types of objects, how would one test for these objects?

Will this work?

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

...assuming Symbol is the eventual name for Private Names.

Should I use this?

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

... or something else?


The reason I ask is I am currently writing code that I want to be able to transition as easily as possible to ES6 in a year or two when possible. If there is a replacement for Object.prototype.toString, then I can just shim it in and continue from there. Thanks!


Update

benvie's answer provided me with the correct term to search for and understand the answer to my questions.

I found an email from Allen Wirfs-Brock on es-discuss concerning this issue.

Here's what I found, for anyone else asking the same questions:

1. Do Chrome and Firefox behave correctly?

Yes, why is explained below.

2. Is there an alternative to Object.prototype.toString?

As it is now, there will be a couple "alternatives" in the sense of possibilities, but not in the sense of replacements.

a. Using the @@toStringTag symbol. However, my understanding is that Object.prototype.toString should still probably be used. @@toStringTag is provided to allow extending the results that can be returned from Object.prototype.toString. If you have a prototype you would like to add your own string tag to, you could use @@toStringTag to set the value to any string. Object.prototype.toString will return this value except in the case where this value is one of the ES5 built-ins, in which case the string tag will be prepended with '~'.

b. Using private symbols on user-defined objects. I read one email promoting this as the best way to do the same type of check on a user-defined object. However, I don't see how that really settles the issue, as I fail to understand how it could be a cross-frame solution and it doesn't let you check against ES6 built-ins.

So even though there are some alternatives, it's good to stick with Object.prototype.toString now and going forward, with one caveat:

It'll work to make sure you have an ES5 built-in, such as String, but it won't be fool-proof to make sure you have an ES6 built-in because they can be spoofed with @@toStringTag. I'm not sure why this is, and I may be missing something, or it could change as the spec evolves.

3. Since [[NativeBrand]] seems like it won't include future types of objects, how would one test for these objects?

As mentioned above, Object.prototype.toString can still be used on ES6 built-ins, but it's not fool-proof as it can be spoofed by anyone with access to the @@toStringTag symbol. However, maybe there shouldn't be a fool-proof method, since Object.prototype.toString(weakmap) == '[object WeakMap]' doesn't mean that weakmap instanceof WeakMap (and it shouldn't!). The weakmap could have come from another frame, or it could be a user-created weakmap-like object. The only thing you really know is it reports to be functionally equivalent to a WeakMap.

It does seem to beg the question why you can't have a user-defined object which reports to be functionally equivalent to a String or Array (sans the prefixed "~").

解决方案

This is currently a moving target in the ES6 spec. For the existing set of objects, the existing mechanics are maintained for various reasons including compatibility. In the most recent ES6 spec, published October 26th, you can find some hints of the potential future direction

15.4.6.2.4 ArrayIterator.prototype.@@toStringTag
The initial value of the @@toStringTag property is the string value "Array Iterator".

15.14.5.13 Map.prototype.@@toStringTag
The initial value of the @@toStringTag property is the string value "Map".

You can find the original discussion that originated this in this thread on es-discuss

这篇关于访问ES6中的[[NativeBrand]] / [[Class]](ECMAScript 6)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆