为什么扩展本机对象是一种不好的做法?

每个JS意见领袖都说扩展本机对象是一种不好的做法。但是为什么?我们是否得到了性能上的打击?他们是否担心有人以“错误的方式”这样做,并将可枚举类型添加到 中,实际上破坏了任何对象上的所有循环?Object

TJ Holowaychuk.js为例。他添加了一个简单的getter,一切都很好(来源)。Object

Object.defineProperty(Object.prototype, 'should', {
  set: function(){},
  get: function(){
    return new Assertion(Object(this).valueOf());
  },
  configurable: true
});

这确实是有道理的。例如,可以扩展.Array

Array.defineProperty(Array.prototype, "remove", {
  set: function(){},
  get: function(){
    return removeArrayElement.bind(this);
  }
});
var arr = [0, 1, 2, 3, 4];
arr.remove(3);

是否有任何反对扩展本机类型的论点?


答案 1

扩展对象时,会更改其行为。

更改仅由您自己的代码使用的对象的行为是可以的。但是,当您更改其他代码也使用的内容的行为时,存在破坏其他代码的风险。

当涉及到在javascript中向对象和数组类添加方法时,由于javascript的工作方式,破坏某些东西的风险非常高。多年的经验告诉我,这种东西会导致javascript中各种可怕的错误。

如果需要自定义行为,最好定义自己的类(可能是子类),而不是更改本机类。这样你就不会破坏任何东西。

在不子类化的情况下更改类的工作方式的能力是任何优秀编程语言的重要功能,但它必须很少使用且要谨慎使用。


答案 2

没有可衡量的缺点,比如性能下降。至少没有人提到任何东西。所以这是一个个人偏好和经验的问题。

主要赞成论点:它看起来更好,更直观:语法糖。它是特定于类型/实例的函数,因此应专门绑定到该类型/实例。

主要的反驳论点:代码可能会干扰。如果 lib A 添加了一个函数,它可能会覆盖 lib B 的函数。这可以很容易地破坏代码。

两者都有道理。当您依赖两个直接更改类型的库时,您很可能会得到损坏的代码,因为预期的功能可能不相同。我完全同意这一点。宏库不得操作本机类型。否则,作为开发人员,您将永远不知道幕后到底发生了什么。

这就是我不喜欢像jQuery,下划线等库的原因。不要误会我的意思。它们绝对编程良好,它们像魅力一样工作,但它们很大。你只使用其中的10%,并且理解大约1%。

这就是为什么我更喜欢原子论的方法,你只需要你真正需要的东西。这样,您始终知道会发生什么。微型图书馆只做你希望它们做的事情,所以它们不会干扰。在让最终用户知道添加了哪些功能的上下文中,扩展本机类型可以被认为是安全的。

TL;DR如有疑问,请勿扩展本机类型。仅当您 100% 确定最终用户将了解并希望该行为时,才扩展本机类型。在任何情况下都不会操作本机类型的现有函数,因为它会破坏现有接口。

如果您决定扩展该类型,请使用 Object.defineProperty(obj, prop, desc);如果不能,请使用类型的 .prototype


我最初提出这个问题是因为我希望通过JSON发送。所以,我需要一种方法来将它们串起来。 感觉比;正如第二种结构所暗示的那样,我正在操作而不是对自己操作。Errorerror.stringify()errorlib.stringify(error)errorliberror