2013-02-18 10 views
6

質問:なぜこのJavaScriptプロトタイプ関数はjQueryを中断しますか?

とすぐに私は私のhtmlページに以下のコードを追加すると、私が手:

Line: 4 
Error: Object doesn't support the property or method "exec". 

これはバグの原因となるプロトタイプです:

Object.prototype.allKeys = function() { 
     var keys = []; 
     for (var key in this) 
     { 
      // Very important to check for dictionary.hasOwnProperty(key) 
      // otherwise you may end up with methods from the prototype chain.. 
      if (this.hasOwnProperty(key)) 
      { 
       keys.push(key); 
       //alert(key); 
      } // End if (dict.hasOwnProperty(key)) 

     } // Next key 

     keys.sort(); 
     return keys; 
    }; // End Extension Function allKeys 

そして、これがありますエラーを再現するために必要な最小限のコード(問題のブラウザ:IE9):

<!DOCTYPE html> 
<html> 
<head> 
    <title>TestPage</title> 

    <script type="text/javascript" src="jquery-1.9.1.min.js"></script> 


    <script type="text/javascript"> 
     /* 
     Object.prototype.getName111 = function() { 
      var funcNameRegex = /function (.{1,})\(/; 
      var results = (funcNameRegex).exec((this).constructor.toString()); 
      return (results && results.length > 1) ? results[1] : ""; 
     }; // End Function getName 
     */ 

     Object.prototype.allKeys = function() { 
      var keys = []; 
      for (var key in this) 
      { 
       // Very important to check for dictionary.hasOwnProperty(key) 
       // otherwise you may end up with methods from the prototype chain.. 
       if (this.hasOwnProperty(key)) 
       { 
        keys.push(key); 
        //alert(key); 
       } // End if (dict.hasOwnProperty(key)) 

      } // Next key 

      keys.sort(); 
      return keys; 
     }; // End Extension Function allKeys 

    </script> 

</head> 
<body> 

    <select id="selLayers" name="myddl"> 
     <option value="1">One</option> 
     <option value="2">Twooo</option> 
     <option value="3">Three</option> 
     <option value="4">Text1</option> 
     <option value="5">Text2</option> 
    </select> 


    <script type="text/javascript"> 

     //var dict = { "de": { "Text1": "Ersetzung 1", "Text2": "Ersetzung 2" }, "fr": { "Text1": "Replacement 1", "Text2": "Réplacement 2" }, "it": { "Text1": "Replacemente 1", "Text2": "Replacemente 2" }, "en": { "Text1": "Replacement 1", "Text2": "Replacement 2"} }; 
     /* 
     var languages = dict.allKeys(); 


     for (var j = 0; j < languages.length; ++j) 
     { 
      var strCurrentLanguage = languages[j]; 
      var dictReplacements = dict[strCurrentLanguage] 
      var keys = dictReplacements.allKeys(); 

      //alert(JSON.stringify(dictReplacements)); 
      //alert(JSON.stringify(keys)); 


      for (var i = 0; i < keys.length; ++i) { 
       var strKey = keys[i]; 
       var strReplacement = dictReplacements[strKey]; 

       alert(strKey + " ==> " + strReplacement); 
       //alert('#selLayers option:contains("' + strKey + '")'); 
       //$('#selLayers option:contains("' + strKey + '")').html(strReplacement); 
       //$('#selLayers option:contains("Text1")').html("foobar"); 


      }  
     } 
     */ 


     $('#selLayers option:contains("Twooo")').text('Fish'); 


     //alert(dict.allKeys());   
     //alert(dict["de"]["abc"]); 




     /* 

     $('#selLayers option[value=2]').text('Fish'); 
     $('#selLayers option:contains("Twooo")').text('Fish'); 
     $('#selLayers option:contains("Twooo")').html('&Eacute;tage'); 
     // http://stackoverflow.com/questions/7344220/jquery-selector-contains-to-equals 

     $("#list option[value=2]").text(); 

     $("#list option:selected").each(function() { 
      alert($(this).text()); 
     }); 

     $("#list").change(function() { 
      alert($(this).find("option:selected").text()+' clicked!'); 
     }); 

     */ 

    </script> 

</body> 
</html> 

プロトタイプ関数の名前を変更しようとしましたが、jqueryプロトタイプと衝突する場合がありますが、それはまったく役に立ちません。

+0

可能なデュープhttp://stackoverflow.com/questions/1827458/prototyping-object-in-javascript-breaks-jquery – zsong

+0

あなたの質問は十分に答えてきました。回答の1つを受け入れることを自由に感じてください:) – benekastah

答えて

6

これは、すべての単一のオブジェクトに列挙可能な項目を追加するためです。 Sizzle(jQueryが使用する)は、オブジェクトリテラルを使用してセレクターの解析を設定します。これらの設定オブジェクトをループしてすべてのトークンを取得すると、あなたの機能は期待できません。この場合、おそらくあなたの関数をRegExpとして使用しようとしています。

は、このシナリオを想像:

var obj = { a: 1, b: 2, c: 3 }; 
var result = 0; 
for (var prop in obj) { 
    // On one of these iterations, `prop` will be "allKeys". 
    // In this case, `obj[prop]` will be a function instead of a number. 
    result += obj[prop] * 2; 
} 
console.log(result); 

あなたが番号として使用することはできませんObjectのプロトタイプに何かを追加した場合、あなたはあなたの結果のためにNaNを取得します。

allKeys関数をObject.prototypeの代わりにObjectに追加するとよいでしょう。この模倣Object.keys

Object.allKeys = function (obj) { 
    var keys = []; 
    for (var key in obj) 
    { 
     // Very important to check for dictionary.hasOwnProperty(key) 
     // otherwise you may end up with methods from the prototype chain.. 
     if (obj.hasOwnProperty(key)) 
     { 
      keys.push(key); 
      //alert(key); 
     } // End if (dict.hasOwnProperty(key)) 

    } // Next key 

    keys.sort(); 
    return keys; 
}; // End Extension Function allKeys 
+1

私は[システム](http://stackoverflow.com/users/1917390/the-system)とこれに行くつもりです。ネイティブプロトタイプにプロパティを追加するのは悪い考えです。 jQueryはjavascriptのfor ... inループの実装がうっとりしているだけで、プロトタイプ関数を壊すことはありません。 – benekastah

+1

ええ、ループのためにおかしい、私はこのコードを書いたときに気づいた。それは、私がallKeysメソッドを思いついた理由です。他の人が単にhasOwnPropertyをチェックしないのであれば、それは本当に良い考えではありません。私はあなたにupvoteを与えて答えを受け取ります:) –

3

jQueryが.hasOwnProperty()列挙オブジェクトをチェックしてそのコードを行き詰まらしないので。

これを実行するには、不適切なコーディング方法に対してガードを配置します。そのような慣行に対応するためにコードを崩すのではなく、ユーザは、Object.prototypeに列挙可能なプロパティを決して置かないように、良い慣行を遵守する必要があります。あなたはこれらのプロパティに対してガードを実行するためにすべてのコードを使用する場合に限り言い換えれば

は... Object.prototypeに列挙プロパティを追加しないでください、あなたはは継承されたプロパティを列挙したいことはありません。


FWIWあなたが本当にプレーンなオブジェクトのメソッドを呼び出したい場合は、あなたが安全に拡張することができ、中間プロトタイプオブジェクトを持つように、単にコンストラクタを作ります。

function O(o) { 
    if (!(this instanceof O)) 
     return new O(o) 
    for (var p in o) 
     this[p] = o[p] 
} 

O.prototype.allKeys = function() { 
    // ... 
}; 

今、あなたはこのようなあなたのオブジェクトを作成します。

var foo = O({ 
    foo: "foo", 
    bar: "bar", 
    baz: "baz" 
}); 

...とObject.prototypeは手付かずのままなので、無地のオブジェクトがまだ安全です。 Oオブジェクトを列挙するときは、.hasOwnProperty()ガードを使用するだけで済みます。

for (var p in foo) { 
    if (foo.hasOwnProperty(p)) { 
     // do stuff 
    } 
} 

そして、解析されてJSONデータに対して、あなたはあなたのOオブジェクトとプレーンなオブジェクトをスワップアウトするリバイバーの機能を使用することができます。

var parsed = JSON.parse(jsondata, function(k, v) { 
    if (v && typeof v === "object" && !(v instanceof Array)) { 
     return O(v) 
    } 
    return v 
}); 
+0

JSONを介して生成された列挙可能な連想配列の型はオブジェクトであるようです。 –

+0

@Quandary:あなたが何を意味するのか分かりません。環境内のすべてのオブジェクトにプロパティー*を継承させると(これは 'Object.prototype'を拡張するときに起こります)*、継承されたプロパティーの反復はすべてバウンドします。 –

+0

はい、それはプロトタイプの感覚です。しかし、本質的に言っているのは、静的メソッドを記述し、変数をオブジェクトに渡す必要があり、悪い習慣を採用するということです.jQueryが悪いコーディング手法を使用しているからであり、逆もありません。 –

3

あなたは記述子を設定することができますdefinePropertyを使用して、この副作用を克服できる可能性があります。

Object.defineProperty(Object.prototype, 'propName', {value: 'your value', enumerable: false}); 
+0

これは現代のブラウザでしかないことを指摘しておきます。 –

+0

真。 JavaScript 1.8.5で導入されました。 – marekful

+0

これはどこでもうまくいけば....そのような素晴らしい解決策。 – benekastah

関連する問題