2009-06-04 150 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); } 
});