重写JavaScript对象和函数的危险

The dangers of overwriting JavaScript object and functions

本文关键字:危险 函数 JavaScript 对象 重写      更新时间:2023-09-26

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

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

Object
Function
Number
String
Boolean
Math
RegExp
Array

让我们假设我想按照Java(和其他一些OOP语言(中的类似模式对这些进行建模,这样Object定义了一组基本函数,每个其他对象都继承它(这必须由用户明确定义,不像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等框架也有类似的方法,这是正确的吗?

Monkey修补这样的内置类是一个有争议的话题。我个人不喜欢这样做2雷亚尔:

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

  2. 在公共类的原型中添加东西可能会破坏使用for in循环的代码,而无需进行hasOwnProperty检查(JS新手经常对对象和数组这样做,因为for in看起来有点像foreach循环(。如果你不能100%确定你使用的代码是否安全地用于内循环,那么monkeypatchingObject.prototype可能会导致问题。

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

这里有一定程度的偏好,但我个人认为这类事情有可能成为一个巨大的棘手问题。

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

项目A决定String需要一个isEmpty函数,如果字符串为零长度或仅为空白,则该函数将返回true

项目B决定,如果字符串为零长度,则String需要返回trueisEmpty函数;如果字符串为零时长或仅为空白,则需要返回trueisEmptyOrWhitespace函数。

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

请注意,这与C#中的扩展方法非常不同,在C#中,您至少必须导入包含静态类的命名空间才能获得扩展方法,没有运行时冲突,并且可以在同一项目中合理地使用A和B,只要你不导入它们的扩展命名空间(希望它们有先见之明,正是出于这个原因,将它们的扩展类放在一个单独的命名空间中(。

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

你可以做undefined = 'blah';之类的事情。。。。此时,您就不能再依赖if(x === undefined)了。这可能很容易破坏代码中的其他部分(当然,也可能破坏您可能正在使用的第三方库(。

这完全是疯了,但肯定表明了任意覆盖内置对象的危险性。

另请参阅:http://wtfjs.com/2010/02/15/undefined-is-mutable

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

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

然而,我想你会发现这纯粹是观点和风格。