19

組み込みの配列を使用せずに、JavaScript で配列のようなオブジェクトを作成する方法はありますか? 私は特に次のような行動に関心があります。

var sup = new Array(5);
//sup.length here is 0
sup[0] = 'z3ero';
//sup.length here is 1
sup[1] = 'o3ne';
//sup.length here is 2
sup[4] = 'f3our';        
//sup.length here is 5

ここで見ている特定の動作は、メソッドが呼び出されることなく sup.length が変更されることです。この質問から、配列の場合 [] 演算子がオーバーロードされていることがわかりました。これがこの動作の原因です。この動作を再現する純粋な JavaScript の方法はありますか、それとも言語が十分に柔軟でないのでしょうか?

Mozilla docsによると、正規表現によって返される値も、このインデックスで奇妙なことを行います。これはプレーンなJavaScriptで可能ですか?

4

10 に答える 10

23

[] 演算子は、オブジェクト プロパティにアクセスするためのネイティブな方法です。動作を変更するためにオーバーライドする言語では使用できません。

[] 演算子で計算された値を返すことが必要な場合、言語は計算されたプロパティの概念をサポートしていないため、JavaScript ではそれを行うことはできません。唯一の解決策は、[] 演算子と同じように機能するメソッドを使用することです。

MyClass.prototype.getItem = function(index)
{
    return {
        name: 'Item' + index,
        value: 2 * index
    };
}

クラスのネイティブ配列と同じ動作が必要な場合は、ネイティブ配列メソッドをクラスで直接使用することが常に可能です。内部的には、クラスはネイティブ配列と同じようにデータを格納しますが、クラスの状態を保持します。jQuery は、そのメソッドを保持しながら、jQuery クラスに配列の動作を持たせるためにこれを行います。

MyClass.prototype.addItem = function(item)
{
    // Will add "item" in "this" as if it was a native array
    // it will then be accessible using the [] operator 
    Array.prototype.push.call(this, item);
}
于 2008-12-14T01:39:32.920 に答える
13

はい、JavaScript で簡単に配列を配列のようなオブジェクトにサブクラス化できます。

var ArrayLike = function() {};
ArrayLike.prototype = [];
ArrayLike.prototype.shuffle = // ... and so on ...

次に、オブジェクトのような新しい配列をインスタンス化できます。

var cards = new Arraylike;
cards.push('ace of spades', 'two of spades', 'three of spades', ... 
cards.shuffle();

残念ながら、これは MSIE では機能しません。lengthプロパティを追跡しません。それはむしろ全体を収縮させます。

問題の詳細については、Dean Edwards のHow To Subclass The JavaScript Array Object を参照してください。一部のポップアップブロッカーがそれを防ぐため、彼の回避策は安全ではないことが後で判明しました.

更新:この件に関する Juriy "kangax" Zaytsev の非常に壮大な投稿に言及する価値があります。この問題のほぼすべての側面をカバーしています。

于 2008-12-14T04:00:25.197 に答える
3

これはあなたが探しているものですか?

Thing = function() {};
Thing.prototype.__defineGetter__('length', function() {
    var count = 0;
    for(property in this) count++;
    return count - 1; // don't count 'length' itself!
});

instance = new Thing;
console.log(instance.length); // => 0
instance[0] = {};
console.log(instance.length); // => 1
instance[1] = {};
instance[2] = {};
console.log(instance.length); // => 3
instance[5] = {};
instance.property = {};
instance.property.property = {}; // this shouldn't count
console.log(instance.length); // => 5

唯一の欠点は、「長さ」がプロパティであるかのように for..in ループで繰り返されることです。残念ながら、プロパティ属性を設定する方法はありません(これは、私が本当にやりたいことの 1 つです)。

于 2008-12-14T17:25:17.800 に答える
2

答えは、今のところ方法がないということです。配列の動作は ECMA-262 でこのように動作するように定義されており、配列プロパティ (汎用オブジェクト プロパティではなく) の取得と設定を処理する方法について明示的なアルゴリズムがあります。これは私をややがっかりさせます =(。

于 2008-12-14T04:08:36.457 に答える
1

ほとんどの場合、javascript で配列の事前定義されたインデックス サイズは必要ありません。次のようにするだけです。

var sup = []; //Shorthand for an empty array
//sup.length is 0
sup.push(1); //Adds an item to the array (You don't need to keep track of index-sizes)
//sup.length is 1
sup.push(2);
//sup.length is 2
sup.push(4);
//sup.length is 3
//sup is [1, 2, 4]
于 2008-12-14T01:38:43.717 に答える
1

次のような独自の長さメソッドを作成することもできます。

Array.prototype.mylength = function() {
    var result = 0;
    for (var i = 0; i < this.length; i++) {
        if (this[i] !== undefined) {
            result++;
        }
    }
    return result;
}
于 2012-06-27T20:41:12.437 に答える
1

スパース配列のパフォーマンスが気になり (気にする必要はないかもしれませんが)、構造体が渡した要素と同じ長さであることを確認したい場合は、次のようにすることができます。

var sup = [];
sup['0'] = 'z3ero';
sup['1'] = 'o3ne';
sup['4'] = 'f3our';        
//sup now contains 3 entries

繰り返しますが、これを行ってもパフォーマンスが向上する可能性は低いことに注意してください。Javascript はすでにスパース配列を適切に処理していると思います。どうもありがとうございました。

于 2008-12-14T01:40:41.000 に答える
-2

確かに、ほとんどすべてのデータ構造を JavaScript で複製できます。基本的な構成要素はすべてそこにあります。ただし、最終的には遅くなり、直感的ではなくなります。

しかし、 push/pop だけを使用しないのはなぜですか?

于 2008-12-14T01:24:59.503 に答える