13

这段视频中(大约 31 分钟),Crockford 说他们(代表 ECMAScript 委员会发言)建议不要使用Object.getPrototypeOf. 他的解释是,它并不是真正适用于普通开发人员,而是适用于 Caja 之类的东西,这可能会删除它Object以阻止您访问它。

Crockford 有时会在他对如何使用 JS 的看法上固执己见(我们都不能吗?),所以我想知道这是否真的是 ES 委员会的全部建议,或者这只是 Crockford 的个人意见之一。有没有人读过任何官方声明警告不要使用Object.getPrototypeOf?这对我来说听起来真的很糟糕 :(,但我在 MDN 页面上没有看到任何警告使用它的信息,如果它真的是一个糟糕的想法,我希望会有一个通知。

4

1 回答 1

15

他的推理非常糟糕。它(和Object.getOwnPropertyNames)不是为了使用 Caja 和类似而简单添加的。Caja 也不会简单地删除它们!Caja 拦截Object.getOwnPropertyNames以实现WeakMap我的 shim也是如此),据我所知,它不会修改 getPrototypeOf。实际上,无论如何它都是毫无意义的,因为Object.getPrototypeOf(o)它与在除 IE 之外的每个浏览器中实现的相同,o.__proto__并且不能(当前)关闭。这意味着唯一可以删除的浏览器Object.getPrototypeOf是 IE9 和 IE10。

我认为他会给出的原因是其中一些功能主要是供“图书馆作者”类型使用的。这是参与规范过程的人通常相信/说过的话,我相信这是一个合法的主张;属性描述符/属性和其他“元”级 API 是更高级的功能,使用起来很麻烦,通常需要更完整的语言掌握才能正确使用。但是,这仍然不等于“不要使用它们”的一揽子建议。不过,这个更准确的说法甚至不是他提出的论点。

关于视频的一个额外说明,他在其中做了不正确的陈述。他说属性属性(可枚举、可配置、可写)一旦设置就不可更改。这是不正确的。只要configurable是真的,这些都可以改变。一旦设置为 false,属性就会被冻结(属性也不能删除)。


编辑:在完成研究之后,我发现了一些关于这个特性和其他对象函数的原始讨论。我理解的总结如下。

人们担心能够访问对象的 [[Prototype]] 会带来安全隐患。然而,这些问题通过 Object.freeze 之类的东西得到了更全面和适当的解决,并且部分解决了(也是一个原因)这些函数作为静态函数(可在一个位置删除)而不是 Object.prototype 或神奇地存在于 Object 上在历史上像proto这样的每个对象上。

提出的另一个问题是破坏封装

确实,proto或 getPrototypeOf 打破了对象的封装障碍,并揭示了可能打算隐藏的实现细节。提议的 getProperty 函数也是如此,除其他外,它使观察者可以访问实现 getter/setter 属性的函数。一般来说,这就是反射的本质。-Allen Wirfs-Brock

从实现端提出的一个问题是关于暴露实现细节(主要是源于 DOM 如何工作的问题,此后通过更改 DOM 对多重继承的使用和向 WebIDL 的过渡解决了这一问题)。

另一方面,提供对对象原型的反射访问对兼容性有害,因为它会阻止实现在不破坏网络的情况下引入中间原型。考虑只有 Numbers 的例子,然后兼容地引入更具体的 Numbers 子类。——瓦尔德玛·霍瓦特

这个问题也与脚本协调邮件列表中提到的另一个问题有关,即内部隐藏原型是相同的跨框架。这个问题也是 ES5(和 IE8)的历史,它决定并实现每个框架必须实例化自己的一组 DOM 原型。因此,到 ES5 正式发布时,由于这个原因隐藏原型不再相关。


我看到的共识不符合 Crockford 的解释。大多数情况下,这似乎只是他自己观点的重申。

总之,不提供对对象原型的反射访问并不能真正提供任何真正的安全性,它只会使一些有用的任务不那么方便。 -Allen Wirfs-Brock


总的来说,我同意你的看法,很高兴听到反射不是“真正的安全”的敌人。 ——布伦丹·艾希

这方面的出发点是提议的 ECMAScript 3.1 静态对象函数:用例和基本原理(由 Crockford 和其他人在 TC39 上编写)。后续,我从中引用,是这个 es-discuss 线程。特别是这篇文章这篇文章

于 2012-10-04T03:32:38.637 回答