0

WebアプリのメインJavaScriptに次のコードがあります。

    // uniq for arrays
if (!Array.prototype.getUnique) {
    Array.prototype.getUnique = function () {
        var u = {}, a = [];
        for (var i = 0, l = this.length; i < l; ++i) {
            if (u.hasOwnProperty(this[i])) {
                continue;
            }
            a.push(this[i]);
            u[this[i]] = 1;
        }
        return a;
    }
}

これはjavascriptの単純なuniqクローンであり、基本的なArrayクラスにmonkeypatchedされています。(モンキーパッチについて議論するためにここにいるのではなく、他の場所で炎を上げてください...)

getUnique()意図したとおりに機能しますが、ループを使用して配列を反復処理するたびに、for...in呼び出される追加のインデックスgetUniqueがイテレータ本体に渡され、このfalsenが検索されると、getUniqueのコードが値になります。(言い換えるfor...inと、配列をループしているはずですがgetUnique、最後の反復としてaを追加しています)

ここで何が起こっているのですか?この関数のすぐ上に、正常に機能し(indexOf())、イテレータに表示されない別の関数があります。この問題を引き起こすいくつかのサンプルコードを次に示します。

for (var r in result) {
    //tags = tags + result[r]["tags"].split(" ").join(", ")
    if (result[r]["tags"]) {
        var newtags = result[r]["tags"].split(" ");
        debug.log(newtags);
        for (var n in newtags) {
            debug.log("n is " + n);
            tags.push(newtags[n]);
        }
    }
}

このスニペットからのデバッグ出力は次のようになります。

[14:22:26.090] [["camp", "furnitur", "wood"]]
[14:22:26.093] ["n is 0"]
[14:22:26.096] ["n is 1"]
[14:22:26.099] ["n is 2"]
[14:22:26.101] ["n is getUnique"]

ここで何が起こっているのですか?モンキーパッチをリファクタリングしてユーティリティクラスにドロップするのは簡単ですが、これは私にとって本当に奇妙なエッジケースです。私はここで何が起こっているかについて頭の中でいくつかの考えを持っていますが、それらは単なる推測です。誰か説明できますか?

4

4 に答える 4

1

これはhasOwnProperty解決するように設計されたものです。繰り返した名前がオブジェクト自体にあるのか、プロトタイプから継承されたのかを示します。

これを試して:

for (var n in newtags) {
    if (newtags.hasOwnProperty(n)) {
        debug.log("n is " + n);
        tags.push(newtags[n]);
    }
}
于 2012-07-14T12:38:46.883 に答える
1

for-in数値プロパティの反復には使用しないでください。

forループを使用します。

 for (var i = 0; i < newtags.length; i++) {

このfor-inステートメントは、この仕事に適したツールになることはほとんどありません。なぜなら...

  • これには、非数値、範囲外、およびプロトタイプのプロパティを含むすべてのプロパティが含まれます。

  • 列挙の順序を保証するものではありません。


チェックを行うことはできますがhasOwnProperty、実際のメリットはなく、いくつかのデメリットがあります...

  • それはあなたの反復を遅くします

  • 列挙の順序の問題には役立ちません

  • プロトタイプのインデックスが必要な場合があります(まれですが、発生します)。使用hasOwnPropertyするとこれが不可能になります。

于 2012-07-14T12:39:41.580 に答える
1

for…inオブジェクトのプロパティを列挙することを目的としたループを使用して配列を反復処理しないでください。したがって、たとえば、インデックスの順序については保証されません。また、ご覧のとおり、数値インデックスのみを反復することも保証されません。他の誰かがそのような方法で配列のプロトタイプにプロパティを追加した場合、あなたもそのプロパティを繰り返します。全体像を把握するには、 https://developer.mozilla.org/en/JavaScript/Reference/Statements/for...inを参照してください。

ただし、あなたの場合、次のことができます。

for (var n in newtags) {
    if (newtags.hasOwnProperty(n)) {
        debug.log("n is " + n);
        tags.push(newtags[n]);
    }
}

また、他のスクリプトによってプロトタイプに追加されたプロパティを繰り返すこともできなくなります。また、関数を列挙できないものとして定義することもできます(ES5がサポートされているブラウザーで)。

Object.defineProperty(Array.prototype, "getUnique", {
    value: function () { /*.. your function ..*/}
})

参照:https ://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/defineProperty

于 2012-07-14T12:43:07.950 に答える
1

よくある誤解は、for ... in操作は、javascriptでは、配列を反復するように作成されているというものです。これは間違っています。その使用法は、オブジェクトの列挙可能なプロパティを反復処理することです。javascriptでは、すべてがオブジェクトです(配列が含まれます)。ただし、配列で...を実行すると、長さやスライスなどの値が取得されないことに気付く場合があります。これは、これらがオブジェクトの列挙可能なプロパティではないためです。

このSOの質問には、for ...inの使用法に関するいくつかの非常に優れた情報があります。配列の反復で「for...in」を使用するのはなぜ悪い考えですか?

for ... inの使用に固執したい場合は、上記で提案したように実行し、for...in内のhasOwnPropertyを確認してください。

for ( var v in myArray ) {
    if ( myArray.hasOwnProperty(v) ) {
        // Do Something
    } 
}

ただし、昔ながらの退屈なループを使用することをお勧めします...

for ( var i = 0; i <= myArray.length - 1; i++ ) {
    // Do Something
}

配列の「インデックス」は実際にはインデックスではなく、対応するインデックスと一致する名前(1、0、4など)を持つプロパティであるため、詳細に立ち入ることなく、これは追加のメソッドにヒットすることなく機能します。

javascriptでは、プロパティが数値の場合、ドット表記のプロパティにアクセスできないため、インデックスのように感じられます(つまり、myArray.0は機能しません)。したがって、myArray [0]を実行すると、配列のように感じられます。

于 2012-07-14T12:54:34.193 に答える