6

質問:

以下のコードを 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 プロトタイプと競合する場合に備えて、プロトタイプ関数の名前を変更しようとしましたが、まったく役に立ちません。

4

3 に答える 3

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関数を追加することです。これは模倣します:ObjectObject.prototypeObject.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
于 2013-02-18T17:13:58.180 に答える
3

.hasOwnProperty()jQueryは、オブジェクトを列挙するときのチェックでコードを詰まらせないためです。

そうすることは、悪いコーディング慣行に対する警備員を配置することです。そのような慣行に対応するためにコードを比較検討するのではなく、ユーザーがに列挙可能なプロパティを決して置かないなどの優れた慣行に従うことを要求します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手つかずのままなので、プレーンなオブジェクトはまだ安全です。.hasOwnProperty()オブジェクトを列挙するときは、ガードを使用する必要がありOます。

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

また、解析されるJSONデータに関しては、reviver関数を使用して、プレーンオブジェクトをオブジェクトと交換できOます。

var parsed = JSON.parse(jsondata, function(k, v) {
    if (v && typeof v === "object" && !(v instanceof Array)) {
        return O(v)
    }
    return v
});
于 2013-02-18T17:14:21.933 に答える
3

defineProperty記述子を設定できる which を使用することで、この副作用を克服できる場合があります。

Object.defineProperty(Object.prototype, 'propName', {value: 'your value', enumerable: false});
于 2013-02-18T17:21:05.273 に答える