6

JavaScript 的本质允许完全重写其原生对象。我想知道这样做是否有任何真正的危险!

以下是本机 JavaScript 对象的一些示例

Object
Function
Number
String
Boolean
Math
RegExp
Array

让我们假设我想对它们进行建模以遵循您可能在 Java(和其他一些 OOP 语言)中找到的类似模式,以便 Object 定义一组基本函数,并且每个其他对象都继承它(这必须明确由用户定义,与 Java 不同,Java 中的一切都自然地派生自对象)

例子:

Object = null;
function Object() {
   Object.prototype.equals = function(other) {
      return this === other;
   }

   Object.prototype.toString = function() {
      return "Object";
   }

   Object.equals = function(objA, objB) {
      return objA === objB;
   }
}

Boolean = null;
function Boolean() {
}
extend(Boolean, Object);  // Assume extend is an inheritance mechanism

Foo = null;
function Foo() {
   Foo.prototype.bar = function() {
      return "Foo.bar";
   }
}

extend(Foo, Object);

在这种情况下,Object 和 Boolean 现在有了新的实现。在这方面,可能会发生什么?我可能会进一步破坏事情吗?

编辑:

我在某处读到 MooTools 和 Prototype 等框架有类似的方法,这是正确的吗?

4

4 回答 4

4

像这样的猴子修补内置类是一个有争议的话题。我个人不喜欢这样做有两个原因:

  1. 内置类是一个全局范围。这意味着如果两个不同的模块尝试将具有相同名称的方法添加到全局类中,那么它们将发生冲突,从而导致细微的错误。更微妙的是,如果未来版本的浏览器决定实现一个同名的方法,你也会遇到麻烦。

  2. 向公共类的原型添加东西可能会破坏使用 for-in 循环而不检查 hasOwnProperty 的代码(JS 新手经常对对象和数组这样做,因为 for-in 看起来像一个 foreach 循环)。如果您不能 100% 确定您使用的代码是否安全地使用了 for-in 循环,那么猴子修补 Object.prototype 可能会导致问题。

也就是说,在一种情况下,我发现monkeypatching builtins 是可以接受的,那就是在旧浏览器上添加新浏览器的功能(例如,数组的 forEach 方法)。在这种情况下,您可以避免与未来的浏览器版本发生冲突,并且不太可能让任何人感到意外。但即便如此,我仍然建议使用来自第三方的 shim,而不是自己编写代码,因为通常有很多棘手的极端情况很难解决。

于 2013-01-08T19:23:42.733 回答
1

这里有一定程度的偏好,但我个人的看法是,这种事情有可能变成一个巨大的棘手的混乱。

例如,您从两个项目 A 和 B 开始,每个项目都决定在 String 上实现各种非常有用的流利方法。

项目 A 已决定String需要一个isEmpty函数,该函数true在字符串长度为零或仅为空格时返回。

项目 B 决定String需要一个在字符串长度为零时返回的函数,以及isEmpty在字符串长度为零或仅为空格时返回的函数。trueisEmptyOrWhitespacetrue

现在您有一个项目想要使用项目 A 中的一些代码和项目 B 中的一些代码。它们都广泛使用了它们的自定义isEmpty函数。你有机会成功加入两者吗?可能不是。可以这么说,您处于集群安排中。

请注意,这与 C# 中的扩展方法非常不同,在 C# 中,您至少必须导入包含静态类的命名空间才能获取扩展方法,没有运行时冲突,并且可以合理地从同一项目中的 A 和 B 消费因为您没有导入他们的扩展名称空间(希望他们有远见将他们的扩展类放在一个单独的名称空间中,正是出于这个原因)。

于 2013-01-08T19:08:00.347 回答
0

我所知道的 JS 中最糟糕的情况是undefined. 你可以定义它。

您可以做类似undefined = 'blah';.... 之类的事情,此时您不能再依赖if(x === undefined). 这很容易破坏您代码中其他地方的某些东西(或者,当然,在您可能正在使用的第三方库中)。

这完全是疯狂的,但绝对显示了任意覆盖内置对象的绝对危险。

另见:http ://wtfjs.com/2010/02/15/undefined-is-mutable

举一个更合理的例子,以Sahi 浏览器测试工具为例。此工具允许您为浏览器编写自动化脚本来测试您的站点。(类似于硒)。这样做的一个问题是,如果您的站点使用alert()or confirm(),则脚本将在等待用户输入时停止运行。Sahi 通过用自己的存根函数覆盖这些函数来解决这个问题。

于 2013-01-08T17:31:41.857 回答
0

我避免覆盖固有对象的默认行为。它咬了我几次,而其他我很好。Sugar.js 是您可以查看示例的库。它是一些人喜欢的一个很棒的库,但我通常会避免它,因为它扩展了现有 JavScript 对象的行为,例如你正在做的事情。

但是我认为您会发现这纯粹是观点和风格。

于 2013-01-08T18:40:44.187 回答