不要使用getPrototypeOf?

13
这个视频中(大约在31分钟处),Crockford表示,他们(代表ECMAScript委员会)建议不要使用Object.getPrototypeOf。他的解释是,它并不是真正针对普通开发者而设计的,而是针对像Caja这样的东西,可能会从Object中移除它以防止你访问它。
Crockford有时候对JS应该如何使用持有强烈看法(我们都可以吧?),所以我想知道这是否是ES委员会的全面建议,还是只是Crockford的个人意见。有人读过任何正式声明,警告不要使用Object.getPrototypeOf吗?这对我来说听起来确实有点糟糕 :( 但是我没有看到MDN页面上有关于其使用的警告,如果真的是那么糟糕的想法,我会期望看到一个通知。

1
我现在没有时间写一个完整的答案,但是我发现了一些事情:1.__proto__并不明显是一个巨大的安全问题,但 Brendan Eich 反对添加它,因为它是非标准的,并暴露了不必要的攻击面(Mario Heiderich 在他的博士论文中稍微扩展了一下安全影响);2. Douglas 最早在2008年以明确的方式提出了这个观点。 - Jordan Gray
这个问题是有争议的,主要提供有观点的答案。这里没有对错之分。虽然有些担忧是合理的,但应该用不同的方式表达。 - Robert Koritnik
1个回答

15

他的推理非常糟糕。它(以及 Object.getOwnPropertyNames)并不仅仅是为了 Caja 和类似工具而添加的。Caja 也没有简单地删除它们!Caja 拦截 Object.getOwnPropertyNames 以实现 WeakMap(我的 my shim 也一样),据我所知它并不修改 getPrototypeOf。事实上,这样做是毫无意义的,因为 Object.getPrototypeOf(o)o.__proto__ 是相同的,在除 IE 之外的所有浏览器中都已经实现,并且不能(目前)被关闭。这意味着从中删除 Object.getPrototypeOf 只会影响 IE9 和 IE10。

我认为他的原因是其中一些函数主要是为“库作者”类型的用法而设计的。这是规范制定过程中常见的信念/说法,我认为这是一个合理的观点;属性描述符/属性和其他“元”级别的API是更高级的功能,使用起来可能很麻烦,并且通常需要更完整的语言掌握才能正确使用。然而,这仍然不能成为“不要使用它们”的全面建议。尽管如此,他并没有提出这个更准确的观点作为争论的论点。
关于视频的一个额外说明,他说属性属性(可枚举,可配置,可写)一旦设置就无法更改。这是不正确的。只要configurable为true,这些可以更改。一旦设置为false,属性就会被冻结(也不能删除属性)。

编辑:经过调查,我找到了关于这个功能和其他对象函数的原始讨论。据我所知,总结如下。

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

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

确实,proto或getPrototypeOf打破了对象的封装屏障,并揭示了可能意图隐藏的实现细节。同样,对于所提出的getProperty函数,它使观察者可以访问实现getter/setter属性的函数,这也可以说是反射的本质。-Allen Wirfs-Brock

从实现端提出的一个问题是暴露实现细节(主要是源自DOM的工作方式的担忧,但已通过对多重继承的使用以及转向WebIDL进行了改变)。

另一方面,为对象的原型提供反射访问会对兼容性造成影响,因为它会防止实现引入中间原型而破坏网络。考虑一个例子,只有数字,然后再兼容地引入更具体的数字子类型。- Waldemar Horwat
这个问题也与脚本协调邮件列表中提到的另一个问题有关,即内部隐藏原型在跨帧时相同。这个问题在ES5(和IE8)时已经历史了,当时决定并实施每个帧必须实例化其自己的DOM原型集合。因此,由于这个原因隐藏原型在ES5正式发布时已不再相关。
我看到的共识并不遵循Crockford的解释。大多数情况下,它似乎只是他自己观点的重申。
总之,不提供对对象原型的反射访问并不能真正提供任何安全保障,只会使一些有用的任务变得不太方便。 - Allen Wirfs-Brock
我总体上同意你的观点,并且很高兴听到反射并不是“真正安全”的敌人。 - Brendan Eich
这个的起点是拟议的 ECMAScript 3.1 静态对象函数:用例和原理(由 Crockford 和 TC39 的其他成员编写)。我引用的后续内容来自这个 es-discuss 线程,具体来说是这篇文章这篇文章

不错的回答。你的第二段非常相关,我认为...也许值得补充一下,如果你不是在编写库级别的代码,你应该能够自己维护原型的句柄,或者确保它们作为构造函数的属性可用...在自包含的、非库级别的代码中,你真的不应该需要使用 getPrototypeOf - Dagg Nabbit
+1 感谢您的回答。这正是我想要听到的,因为作为一个库开发者,我肯定希望可以自由地使用 getPrototypeOf。如果您不介意,我希望再等几天才决定是否接受答案/奖励赏金,因为我真的很想知道 ES 委员会中是否有人对 Crockford 的说法进行了任何评论或澄清。但是,如果没有更具体的信息出现,我一定会接受并给予奖励的。谢谢! - Nathan Wall
感谢您!除了库构建和元编程之外,GetOwnPropertyNames 的用途很少,因此稍微降低其效率是为了获得集合提供的好处而付出的小代价。关于您的其他评论,我会看看能否在今天晚些时候用一些原始参考资料来完善答案。 - user748221
1
我忘记完成我的发现并发布它们了!这篇文章已经被编辑,包含了你需要的信息。 - user748221
很高兴你链接到了那个线程,这是我第一次看到 Caja 被用作 getPrototypeOf 的具体理由。(顺便说一句,我想知道如果有人问,Douglas 会不会介意?他似乎是一个非常友好的人,而且他的电子邮件地址可以从他的 Github 页面上公开获取。) - Jordan Gray
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接