2009-06-04 115 views
32

我正在开发支持AJAX的asp.net应用程序。 我只是增加了一些方法应用到Array.prototype像将自定义函数添加到Array.prototype

Array.prototype.doSomething = function(){ 
    ... 
} 

该解决方案为我工作,是在一个“漂亮”的方式可能重用代码。

但是,当我测试了它与整个页面一起工作时,我遇到了问题。我们有一些自定义ajax扩展器,它们开始表现为意外:某些控件围绕其内容或值显示“未定义” 。

这可能是什么原因?我错过了修改标准对象原型的东西吗?

注意:我非常肯定,当我修改阵列的原型时,错误开始了。它应该只与IE兼容。

回答

33

修改内置对象原型通常是一个坏主意,因为它总是有可能与同一页面上的其他代码发生冲突。

对于Array对象原型,这是一个特别糟糕的想法,因为它可能会干扰任何数组成员迭代的代码段,例如for .. in

说明使用一个例子(从here借用):

Array.prototype.foo = 1; 

// somewhere deep in other javascript code... 
var a = [1,2,3,4,5]; 
for (x in a){ 
    // Now foo is a part of EVERY array and 
    // will show up here as a value of 'x' 
} 

这将是更好地为您创建自己的类型对象的构造完整的DoSomething的功能,而不是扩展内置阵列。

+6

我相信“for(x in y)”构造用于遍历对象的成员。对于一个数组的基于索引的迭代,我认为它不适合。但是,关于干扰页面上其他代码的观点是有效的 - 特别是如果第三方库以这种方式使用for-in。 – harto 2009-06-04 03:22:26

+5

是的,反过来是正确的 - 你应该避免for..in万一某些n00b修改了数组原型,并且你应该避免修改数组原型,以防n00b在数组中使用。 ;) – thomasrutter 2009-06-04 08:50:07

1

通常搞乱核心JavaScript对象是一个坏主意。你永远不知道任何第三方库可能会期待什么,并改变JavaScript中的核心对象改变他们的一切。

如果你使用Prototype,它特别糟糕,因为原型与全局范围混淆,而且很难判断你是否要碰撞。实际上修改任何语言的核心部分通常是一个坏主意,即使在JavaScript中也是如此。

(LISP可能是小的例外存在)

1

增强泛型类型可以这么说。你可能已经覆盖了一些其他lib的功能,这就是为什么它停止工作。

假设您正在使用的某些库扩展Array与函数Array.remove()。 lib加载后,还可以将remove()添加到Array的原型中,但使用自己的功能。当lib调用你的函数时,它可能会按照预期的不同方式工作,并打破它的执行......这就是发生在这里的事情。

8

请注意!也许你这样做:fiddle demo

让我们说的阵列和方法foo其返回第一个元素:

var myArray = ["apple","ball","cat"]; 

foo(myArray) // <- 'apple' 

function foo(array){ 
    return array[0] 
} 

以上是可以的,因为该功能在解释时隆起顶端。

但是,这并不工作:(因为原型是不是definned)

myArray.foo() // <- 'undefined function foo' 

Array.prototype.foo = function(){ 
    return this[0] 
} 

对于这项工作,只需在上面定义的原型:

Array.prototype.foo = function(){ 
    return this[0] 
} 

myArray.foo() // <- 'apple' 

,是的!你可以重写原型!它被允许。你甚至可以为阵列定义自己的add方法。

25

尽管可能与其他位碰撞代码重写原型上的函数仍然是一个风险,如果你想用现代版本的JavaScript来做这件事,你可以使用Object.defineProperty方法,关闭可枚举位,例如

// functional sort 
Object.defineProperty(Array.prototype, 'sortf', { 
    enumerable: false, 
    value: function(compare) { return [].concat(this).sort(compare); } 
});