2009-06-04 25 views
32

私はAJAX対応のasp.netアプリケーションで作業していました。 は、私はちょうどこのソリューションは、私のために働いたArray.prototypeにカスタム関数を追加する

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

LIKE「きれい」な方法で再利用できるコードであること、Array.prototypeをするためにいくつかのメソッドを追加しました。

しかし、私はそれがページ全体での作業テストしてみたとき、私は問題を抱えていた。.. は、我々はいくつかのカスタムAJAXエクステンダを持っていた、と彼らは予想外のように動作し始めた:表示されたいくつかのコントロールは、その内容や値の周りに「未定義します」 。

何が原因なのでしょうか?スタンドアットオブジェクトのプロトタイプを修正することについて何か不足していますか?

注:Arrayのプロトタイプを変更するとエラーが発生することは間違いありません。 IEとのみ互換性があります。

答えて

33

組み込みオブジェクトのプロトタイプを変更すると、同じページの他のコードと常に衝突する可能性があるため、一般的には悪い考えです。

Arrayオブジェクトのプロトタイプの場合、どの配列のメンバーに対しても反復するコードの一部を妨げる可能性があるため、特に悪い考えです(for .. inなど)。

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の機能を備えた完全なオブジェクトのコンストラクタの独自の型を作成することが良いだろう:(hereから借りた)の例を使って説明するために

+6

"for(x in y)"構文は、オブジェクトのメンバーを反復するためのものだと思います。配列のインデックスベースの反復の場合、私はそれが適切だとは思わない。ただし、ページ上の他のコードを妨害することについてのあなたの要点は有効です。特に、サードパーティのライブラリがこのようにfor-inを使用している場合は有効です。 – harto

+5

はい、その逆は真です - いくつかのn00bが配列プロトタイプを変更した場合、for..inを避けるべきですし、n00bの一部がfor..inを配列に使用した場合にArrayプロトタイプを変更しないでください。 ;) – thomasrutter

+32

最近の_right_は、Object.defineProperty(Array.prototype、 'method'、...)を使って新しいメソッド_non-enumerable_を作ることです。 – Alnitak

1

一般に、JavaScriptのコアオブジェクトを乱用するのは悪い考えです。どのサードパーティのライブラリが期待しているかもしれないか、JavaScriptのコアオブジェクトを変更すると、すべてのものが変更されることは決してありません。

Prototypeを使用すると、プロトタイプがグローバルスコープでも混乱するため、特に悪いことです。衝突するかどうかは分かりません。実際には、どの言語のコア部分も変更するのは、通常はjavascriptでも悪い考えです。

1

あなたはいわばジェネリック型を増強し(Lispはそこに小さな例外かもしれません)。おそらく他のlibの機能を上書きしてしまったので、それが動作を停止した理由です。

使用している一部のlibが、Array.remove()関数を使用してArrayを拡張しているとします。 libがロードされた後、remove()をArrayのプロトタイプに追加しますが、独自の機能を使用します。 libがあなたの関数を呼び出すとき、おそらく期待どおりに動作し、実行を中断します...ここで起こっていることです。

8

注意が必要です!関数は、解釈期間中にトップに隆起しているため、上記の

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

foo(myArray) // <- 'apple' 

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

大丈夫です:

fiddle demoは私たちが最初の要素を返し、配列、メソッドfooが言ってみましょう:たぶん、あなたはそれをやりました。

しかし、これは動作しません:(プロトタイプが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

コードo」は他のビットと衝突する可能性がプロトタイプのオーバーライド機能は、あなたのJavaScriptの最近のバージョンでこれを行うにしたい場合は、あなたがObject.definePropertyメソッドを使用することができ、まだ危険ですが列挙可能ビットをオフにする、例えば

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

'enumerable:false'は' false'が 'enumerable'のデフォルト値であると述べる必要はありません。 – Noitidart

関連する問題