1

重複コードを最小限に抑えて、配列オブジェクトとオブジェクトの両方を反復処理する関数の 1 つのバージョンを作成したいと考えました。何かのようなもの:

function (arr_or_obj) {
   arr_or_obj.forEach( function(key,value) {
            // do stuff with key and value
       });
}

これは、(少なくとも Chrome では)Object.keysが配列のキーのリストを返すことに気付く前のことです。したがって、それを使用して、配列をオブジェクトのように扱うことができます。そのようです:

function (arr_or_obj) {
   var keys = Object.keys(arr_or_obj);
   keys.forEach( function(key) {
            var value = arr_or_obj[key];
            // do stuff with key and value
       });
}

問題が解決しました。しかし、これは私が独自の「JavaScript 疑似配列反復子」を作成する前ではありませんでした。これの唯一の利点は、配列のキーのリスト (非常に長くなる可能性があります) を取得する代わりに、必要な戻り値のみを生成することでメモリを節約できることです。そのようです:

    function create_iterator(max) {
            var jkeys = {};
            jkeys.count_ = 0;
            jkeys.length = max;
            jkeys.getter_ = function() {
                    var returnable = jkeys.count_;
                    jkeys.count_ += 1;
                    jkeys.__defineGetter__(jkeys.count_,jkeys.getter_);
                    delete jkeys[jkeys.count_-1];
                    return returnable;
            };
            jkeys.__defineGetter__(0, jkeys.getter_);
            return jkeys;
    }

次に、次のようにして呼び出すことができます。

var z = create_iterator(100);
z[0];
>> 0
z[0];
>> undefined
z[1];
>> 1;
z[2]
>> 2;
...

これは一種の質問と回答のようなものですが、明らかな質問は、を使用せずにこれを行うより良い方法はありObject.keysますか?

4

3 に答える 3

1

このようなことを試すことができます...
ライブデモ

function forIn(obj) {
    var isArray = Array.isArray(obj),
        temp = isArray ? obj : Object.keys(obj);
    temp.forEach(function (value, index, array) {
        console.log(this[isArray ? index : value]);
    }, obj);
}
于 2013-07-21T09:16:11.207 に答える
1

Object.keysオブジェクト自身の列挙可能なプロパティの配列を提供します。つまり、プロトタイプからではなく、それ自体が持つプロパティであり、列挙可能です (したがって、length列挙不可能なプロパティである配列のようなものは含まれません)。

for-in正しいセーフガードを使用すれば、同じことができます。

var key;
for (key in arr_or_obj) {
    if (arr_or_obj.hasOwnProperty(key)) {
        // do something with it
    }
}

これで、 で行っていたのと同じことを行っていObject.keysます。

ただし、これ (および) には、配列インデックス (JavaScript では完全に有効なもの) ではないObject.keys配列に配置されたプロパティが含まれることに注意してください。例えば:

var key;
var a = [1, 2, 3];
a.foo = "bar";
for (key in a) {
    if (a.hasOwnProperty(key)) {
        console.log(key); // Will show "foo" as well as "0", "1", and "2"
    }
}

配列インデックスのみを処理し、他のプロパティを処理したくない場合は、それが配列であるかどうかを知る必要があります。そうであれば、「これはインデックスですか」テストを使用します。

var key;
var isArray = Array.isArray(arr_or_obj);
// Or (see below):
//var isArray = Object.prototype.toString.call(arr_or_obj) === "[object Array]";
for (key in arr_or_obj) {
    if (a.hasOwnProperty(key) &&
        (!isArray || isArrayIndex(key))
       ) {
        console.log(key);   // Will only show "0", "1", and "2" for `a` above
    }
}

...Array.isArray必要に応じて古いブラウザ用に簡単に調整できる ES5 の新機能は次のとおりです。

if (!Array.isArray) {
    Array.isArray = (function() {
        var toString = Object.prototype.toString;
        function isArray(arg) {
            return toString.call(arg) === "[object Array]";
        }
        return isArray;
    })();
}

...そしてisArrayIndex次のとおりです。

function isArrayIndex(key) {
    return /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294; // 2^32 - 2
}

詳細については、この他の回答を参照してください(マジックナンバーの由来など)。

上記のループは、オブジェクトが配列でない場合はオブジェクト自体の列挙可能なプロパティ (すべて) をループし、配列の場合はインデックスをループします (他のプロパティはループしません)。

さらに一歩進んで、オブジェクトがプロトタイプから取得したプロパティを含めたい場合はどうすればよいでしょうか? Object.keysそれらを省略します(設計による)。それらを含めたい場合hasOwnPropertyは、for-inループで使用しないでください。

于 2013-07-21T08:51:08.437 に答える
0

あなたは書ける:

for (key in arr_or_obj) {
    if (arr_or_obj.hasOwnProperty(key) {
        value = arr_or_obj[key];
        // do stuff with key and value
    }
}
于 2013-07-21T08:44:01.067 に答える