扩展 Object.prototype JavaScript

IT技术 javascript ecmascript-5
2021-01-15 10:45:57

我不是问这是否可以:

Object.prototype.method = function(){};

考虑到它搞砸了,几乎每个人都认为这是邪恶for(var i in obj)

真正的问题

无视

  • 无能的浏览器(不支持的浏览器Object.defineProperty
  • 财产冲突或覆盖的可能性

假设您有一些非常有用的方法,这是否被认为是错误的/不道德的?

Object.defineProperty(Object.prototype, 'methodOnSteriods',{
  value: function(){ /* Makes breakfast, solves world peace, takes out trash */ },
  writable: true,
  configurable: true,
  enumerable: false
});

如果您认为上述内容是不道德的,那么他们为什么要首先实现该功能?

5个回答

2021 年更新

尽管这是公认的答案,但 10 年的经验告诉我这不是最好的主意。几乎任何你能做的避免污染全局范围的事情都是一件非常非常好的事情。

下面的原始答案,为了后代,并且因为堆栈溢出不会让我删除已接受的答案。


2011 年的原始答案

我认为如果它适用于您的目标环境就可以了。

我也认为原型扩展偏执被夸大了。只要你hasOwnProperty()像一个好的开发者一样使用,一切都好。最坏的情况是,您在其他地方重载了该属性并丢失了该方法。但如果你这样做,那是你自己的错。

10 年前,我可能会赞成它 :-) 事情发生了变化,ES6+ 向我们展示了以错误的方式扩展原型如何阻碍语言的进化。
2021-03-20 10:45:57
2021-03-27 10:45:57
哇 10 年是一段很长的时间。我对这个答案有点尴尬。我应该删除它。
2021-04-06 10:45:57
我相信Object.prototype特别是会产生奇怪的边缘情况副作用。但我不确定这是否仅限于旧版浏览器。扩展任何其他原型是安全的。
2021-04-12 10:45:57
是否考虑实施PlainObject基本上var obj = {};Object.defineProperty(PlainObject,'method',{enumerable:false});obj.methd();
2021-04-13 10:45:57

我会说这几乎和以前一样邪恶。最大的问题,仍然和以前一样,是Object.prototype 是 global虽然您的方法目前可能正在解决世界和平,但它可能已经覆盖了其他人的方法(即保证银河和平),或者可能在未来被您无法控制的某个图书馆覆盖(因此使世界再次陷入混乱)


新版本的 Javascript 有许多与属性相关的功能,例如将属性定义为可枚举/不可枚举,具有 getter 和 setter... Object.defineProperty 存在来控制这一点。

来自Mozilla 文档

此方法允许精确添加或修改对象上的属性。通过赋值的正常属性添加会创建在属性枚举(for...in 循环)期间显示的属性,其值可能会更改,也可能会被删除。此方法允许从默认值更改这些额外的详细信息。


这个新功能基本上是支持新功能所必需的,你应该在你自己的东西上使用它。能够修改 Object.prototype 只是它也是一个“正常”对象的副作用,并且和以前一样邪恶。

你能重读这个问题吗,因为我看不出这有什么帮助?Object.prototype两种形式的修改都是邪恶的,还是只有一种?
2021-03-17 10:45:57
@missingno 如果方法名称包含 220 个随机数/字符怎么办?:D 财产冲突是极不可能的:P
2021-03-31 10:45:57
链接可以使代码看起来很棒,但没有它也完全有可能。
2021-04-04 10:45:57
大多数情况下,一个普通的旧函数就可以解决问题,同时更安全和命名空间。如果您真的需要将它用作方法(with this),您可以使用 function.apply 或 function.call。
2021-04-07 10:45:57
根本不回答问题。
2021-04-13 10:45:57

好吧,在“JavaScript:好的部分”中,有一个类似的功能,我认为这对改进 javascript 基础对象(如字符串、日期等)非常有用,但仅此而已。

// Add a method conditionally. from "JavaScript: the good parts"

Function.prototype.method = function (name, func) {
    if (!this.prototype[name]) {
        this.prototype[name] = func;
    }
}

.hasOwnProperty()将通过继承属性排除迭代,我个人认为这通常比帮助更烦人。它在很大程度上破坏了Object.create()- 这具有讽刺意味,因为说服每个人这样做的同一个人.hasOwnProperty()也提升了Object.create()

出于此处列出的原因,不应扩展 Object.prototype。如果你真的想扩展它,那么使扩展不可迭代。

我意识到这与所有已发布的最佳实践背道而驰,但我们真的应该停止“强制”.hasOwnProperty()对象键迭代并接受直接对象到对象继承的用处。

简短的回答是肯定的,你应该这样做。

在做之前,有几个预防措施需要采取:
1.hasOwnProperty迭代对象时使用,但这并不是真正的预防措施,迭代对象时,hasOwnProperty反正我已经在使用了。
2.检查nameinObject.prototype.name是否存在,这样可以很安全的避免名字冲突。
3.利用Object.defineProperty(),只需添加额外的保护层。

如您所见,这不是很复杂。

考虑到风险/缺点后,现在的优点是:
1. 方法链,这只会使代码更具可读性、简洁性,并使编码更有趣。反过来,让你更快乐,让你的生活更轻松。
2.解决了浏览器兼容性问题,反正你是在做polyfill。

PS:
在与大型团队合作时不要这样做。