重写JavaScript对象和函数的危险
The dangers of overwriting JavaScript object and functions
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雷亚尔:
-
内置类是一个全局范围。这意味着,如果两个不同的模块试图将具有相同名称的方法添加到全局类中,那么它们将发生冲突,从而导致细微的错误。更微妙的是,如果未来版本的浏览器决定实现一个同名的方法,你也会遇到麻烦。
-
在公共类的原型中添加东西可能会破坏使用for in循环的代码,而无需进行hasOwnProperty检查(JS新手经常对对象和数组这样做,因为for in看起来有点像foreach循环(。如果你不能100%确定你使用的代码是否安全地用于内循环,那么monkeypatchingObject.prototype可能会导致问题。
也就是说,在一种情况下,我发现monkeypatching内建是可以接受的,那就是在旧浏览器上添加新浏览器的功能(例如,数组的forEach方法(。在这种情况下,您可以避免与未来的浏览器版本发生冲突,也不太可能让任何人感到惊讶。但即便如此,我仍然建议使用第三方的垫片,而不是自己编码,因为通常有很多棘手的角落情况很难解决。
这里有一定程度的偏好,但我个人认为这类事情有可能成为一个巨大的棘手问题。
例如,您从两个项目开始,A和B,每个项目都决定在String上实现各种非常有用的fluent方法。
项目A决定String
需要一个isEmpty
函数,如果字符串为零长度或仅为空白,则该函数将返回true
。
项目B决定,如果字符串为零长度,则String
需要返回true
的isEmpty
函数;如果字符串为零时长或仅为空白,则需要返回true
的isEmptyOrWhitespace
函数。
现在,您有一个项目想要使用来自项目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对象的行为,比如你正在做的事情。
然而,我想你会发现这纯粹是观点和风格。
- 创建一个类似链接的按钮,并通过Javascript函数打开一个新的弹出窗口
- 将函数的上下文应用于javascript变量
- 如何在JavaScript中将字符串转换为函数引用
- 用嵌套函数和默认函数定义函数
- 使用 jQuery 的 .on 函数如何获取事件的原始元素
- 无法导出函数expressjs/requestjs中的变量
- 函数参数中的数据与指定变量之间的任何性能差异
- JQuery合并了keyup和focusout两个函数
- ES6构造函数返回基类的实例
- 监视函数从服务返回不起作用,但作用域函数起作用
- 我可以在json对象中添加一个函数吗
- AngularJS:我可以跳过函数参数回调吗
- 如何使jQuery插件函数可调用以供独立使用,而不在集合上操作
- JavaScript数组排序(函数)用于对表行进行排序,而不是排序
- jquery点击函数select&取消选择
- 拨打'父亲'函数形式a'儿童'ReactJS中的组件
- 直接修改函数有多危险
- 从危险的 SetInnerHtml 内容调用 React 类函数
- 在javascript中,使用回调函数递归地进行循环控制是很危险的
- 重写JavaScript对象和函数的危险