【问题标题】:Extending Object.prototype JavaScript扩展 Object.prototype JavaScript
【发布时间】:2011-07-29 17:51:51
【问题描述】:

我不是在问这是否可以:

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
});

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

【问题讨论】:

  • 这个 defineProperty 设置是沿着原型链传播还是只适用于实际的 Object.prototype 对象?换句话说,如果你碰巧设置了 somevar = {mthodOnSteroids:'mistakeVal'},你是否会丢失 somevar 的定义设置,如 'enumerable: false'?
  • @XHR 是的,你确实失去了你的方法。例如var cards = {forEach:'son'}; cards.forEach(function(){});//world exploids 是的,你确实松了enumerable:false 例如:for(var i in cards)console.log(i); 输出'forEach'

标签: javascript ecmascript-5


【解决方案1】:

2021 年更新

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

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


2011 年的原始答案

我认为如果它在您的目标环境中工作就可以了。

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

【讨论】:

  • 我相信Object.prototype 特别会产生奇怪的边缘情况副作用。但我不确定这是否仅限于旧版浏览器。扩展任何其他原型是安全的。
  • 有没有考虑实现PlainObject。基本上var obj = {};Object.defineProperty(PlainObject,'method',{enumerable:false});obj.methd();
  • 哇,10 年太长了。我对这个答案有点尴尬。我可能应该删除它。
  • 10 年前,我可能会支持它 :-) 事情发生了变化,ES6+ 向我们展示了以错误的方式扩展原型会阻碍语言进化。
【解决方案2】:

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


新版本的 Javascript 具有许多与属性相关的功能,例如将属性定义为可枚举/不可枚举,具有 getter 和 setter...Object.defineProperty 的存在就是为了对此进行控制。

来自Mozilla Docs

此方法允许精确添加或修改属性 在一个物体上。通过赋值添加普通属性会创建 在属性枚举期间显示的属性(for...in 循环), 哪些值可以更改,哪些可以删除。这种方法 允许从默认值更改这些额外的详细信息。


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

【讨论】:

  • 您能否重新阅读这个问题,因为我看不出这有什么帮助?以两种形式修改Object.prototype 是邪恶的,还是只有一种?
  • 根本不回答问题。
  • @missingno 如果方法名称由 220 个随机数/字符组成怎么办? :D 财产冲突极不可能:P
  • 大多数时候,一个普通的旧函数就可以解决问题,同时更安全和命名空间。如果您确实需要将其用作方法(使用 this),您可以使用 function.apply 或 function.call。
  • 链接可以让代码看起来很棒,但没有它也完全可以生存。
【解决方案3】:

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

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

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

【讨论】:

    【解决方案4】:

    .hasOwnProperty() 将排除通过继承属性进行的迭代,我个人认为这通常更烦人而不是有用。它在很大程度上破坏了Object.create() 的用处——具有讽刺意味的是,说服每个人都这样做的同一个人.hasOwnProperty() 也提升了Object.create()

    Object.prototype 不应该被扩展,因为这里列出的原因。如果你真的想扩展它,那么让扩展不可迭代。

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

    【讨论】:

      【解决方案5】:

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

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

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

      处理好风险/劣势后,优势就来了:
      1. 方法链,这只是让代码更易读、更简洁,让编码更有趣。反过来让您更快乐,让您的生活更轻松。
      2. 解决了浏览器兼容性问题,反正你是在做polyfill。

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

      【讨论】:

        猜你喜欢
        • 2013-05-24
        • 1970-01-01
        • 2011-06-30
        • 2012-01-10
        • 1970-01-01
        • 2012-06-22
        • 2013-02-18
        • 2014-12-07
        • 1970-01-01
        相关资源
        最近更新 更多