【发布时间】:2012-10-20 12:56:27
【问题描述】:
我正在阅读 ES6 的草稿,我在Object.prototype.toString 部分注意到了这个注释:
历史上,这个函数偶尔被用来访问字符串 之前使用的 [[Class]] 内部属性的值 本规范的版本作为各种标称类型标签 内置对象。 toString 的这个定义保留了 将其用作那些特定类型的内置对象的可靠测试 但它没有为其他人提供可靠的型式测试机制 各种内置或程序定义的对象。
通过阅读 es-discuss 上的 this thread,听起来 [[Class]] 在 ES6 草案中被 [[NativeBrand]] 替换,以便他们可以将其指定为不可扩展(至少是 Allen Wirfs-Brock's thoughts) .
很好奇,我在 FireFox 和 Chrome 中进行了快速测试(启用了实验性 JavaScript):
Object.prototype.toString.apply(new WeakMap());
=> '[object WeakMap]'
"WeakMap" 不是 ES6 草案中指定的 [[NativeBrand]]s 之一。然而,这个测试在两个浏览器上都返回了"[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.');
这让我知道unknownObject 是否是String 对象,无论它是在什么框架中构造的。
我的问题是,这应该是我进入 ES6 所采用的方法吗?还是有替代方案? Object.getNativeBrandOf 之类的东西?
3。由于[[NativeBrand]] 似乎不会包含未来类型的对象,如何测试这些对象?
这行得通吗?
if (Object.prototype.toString.apply(unknownObject) != '[object Symbol]')
throw new TypeError('Symbol expected.');
...假设 Symbol 是 Private Names 的最终名称。
我应该使用这个吗?
if (Object.prototype.toString.apply(unknownObject) != '[object WeakMap]')
throw new TypeError('WeakMap expected.');
...还是别的什么?
我问的原因是我目前正在编写我希望能够在可能的一两年内尽可能轻松地转换到 ES6 的代码。如果有 Object.prototype.toString 的替代品,那么我可以填充它并从那里继续。谢谢!
更新
benvie 的回答为我提供了正确的术语来搜索和理解我的问题的答案。
我发现 an email from Allen Wirfs-Brock on es-discuss 与此问题有关。
这是我发现的,对于其他提出相同问题的人:
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 并不是万无一失的,因为它们可以被 @ 欺骗987654357@。我不确定为什么会这样,而且我可能遗漏了一些东西,或者它可能会随着规范的发展而改变。
3。由于[[NativeBrand]] 似乎不会包含未来类型的对象,如何测试这些对象?
如上所述,Object.prototype.toString 仍然可以在 ES6 内置函数上使用,但它并不是万无一失的,因为任何可以访问 @@toStringTag 符号的人都可以欺骗它。但是,也许不应该有 防傻 方法,因为Object.prototype.toString(weakmap) == '[object WeakMap]' 并不意味着weakmap instanceof WeakMap(它不应该!)。 weakmap 可能来自另一个框架,或者它可能是用户创建的类似弱图的对象。您真正知道的唯一一件事是它报告在功能上等同于 WeakMap。
这似乎是在问为什么你不能有一个用户定义的对象,它报告在功能上等同于 String 或 Array(没有前缀 "~")。
【问题讨论】:
-
对最后一个问题(关于 ~ 等)的回答是,网络上存在依赖于现有 OptoString 结果值的现有代码,对于现有的 ES5 内置 - ins。我们希望保持这种保证,但仅限于 O.p.toString 在 ES
-
第 32 版删除了
~步骤。 -
"这让我知道 unknownObject 是否是一个 String 对象,无论它是在什么框架中构造的。"不在 Opera 中。
-
在ecma-international.org/ecma-262/6.0,ES6 标准。我没有找到
NativeBrand,所以我猜class没有被NativeBrand取代。
标签: javascript ecmascript-harmony