JavaScript配列の負のインデックスは、配列の長さに寄与する必要がありますか?


84

javascriptで私はこのような配列を定義します

var arr = [1,2,3];

私もできる

arr[-1] = 4;

今私がするなら

arr = undefined;

また、arr [-1]の値への参照を失います。

したがって、論理的には、arr [-1]もarrの一部であるように見えます。

しかし、私がフォローするとき(arrをundefinedに設定せずに)

arr.length;

4ではなく3を返します。

したがって、私のポイントは、配列を負のインデックスで使用できる場合、これらの負のインデックスもその長さの一部である必要があるということです**。自分が間違っているのか、配列に関する概念が欠けているのかはわかりません。


なぜ負のインデックスを使用したいのですか?何かが足りない限り、要点はわかりません。
elclanrs 2012年

11
書くこともできますがarr[1.5] = 1、それも長さに影響しません。言語仕様は、長さに影響するものについて非常に明確です。あなたはそれが好きではないかもしれませんが、あなたはそれと一緒に暮らす必要があります。それか、独自の競合する言語を設計して、人々にそれに切り替えるように説得してください。
レイモンドチェン

1
@DigvijayYadav:JavaScriptの他の多くのものと同様に、欠陥または機能と見なされる可能性があります。これは、配列がオブジェクトのように動作するためです。文字列を使用することもできますvar a = []; a['foo'] = 'baz'が、そうする必要があるわけではありません。それは明らかにすべての慣習に反しています。
elclanrs 2012年

2
皆さん、ここでの要点は、配列はオブジェクトであるということです。違いはありません。これがこの動作の理由であり、気に入らなくても完全に意図的なものです。すべての数値が整数であっても浮動小数点として表されることがわかるまで待ってください。JavaScriptは...好奇心の言語である
トニーR

2
配列要素の設定を定義するアルゴリズムの詳細は、仕様に記載されています:es5.github.com/#x15.4.5.1。(特にステップ4)および「配列インデックス」はここで定義されています:es5.github.com /#x15.4
Felix Kling 2012年

回答:


109

したがって、論理的には、arr [-1]もarrの一部であるように見えます。

はい、そうですが、あなたが思っている方法ではありません。

配列に任意のプロパティを割り当てることができます(JavaScriptの他のオブジェクトと同じように)。これは、配列に「インデックスを付け」て-1値を割り当てるときに行うことです。これは配列のメンバーではなく、単なる任意のプロパティであるため、lengthそのプロパティを考慮することを期待しないでください。

言い換えると、次のコードは同じことを行います。

var arr = [1, 2, 3];

​arr.cookies = 4;

alert(arr.length) // 3;

31
わかりました。つまり、負のインデックスは実際には実際のインデックスのようには機能しません。
me_digvijay 2012年

4
そうです、それらは配列上の任意のプロパティにすぎません。
Andrew Whitaker

しかし、インデックスとは異なり、プロパティとして正のインデックスを使用したいが、それらが配列の長さに寄与したくない場合はどうなりますか?
me_digvijay 2012年

7
次に、配列を使用せず、プレーンなol 'オブジェクトを使用します。ただし、その場合、組み込みのlengthプロパティは失われます。
Andrew Whitaker

2
@Digvijay:コンソールは正の整数名のプロパティのみを表示します。これは(私が推測する)、forから0への通常のループを実行するだけだから.lengthです。やるconsole.dir(arr)完全なオブジェクトを参照してください。また、ブラケット表記を使用して配列にアクセスすることは、配列の特性ではなく、オブジェクトの固有の特性です(var obj = {foo: 'bar'}; obj.foo or obj['foo'])。
Felix Kling 2012年

25

lengthプロパティは、配列「インデックス」は、ゼロ以上の整数で最高割り当て「インデックス」、よりナンバーワン高い戻ります。JSでは「スパース」配列が許可されていることに注意してください。

var someArray = [];
someArray[10] = "whatever";
console.log(someArray.length); // "11"

もちろん、要素がない場合length0です。最高の要素を削除するためにlength使用deleteした場合、は更新されないことにも注意してください。

ただし、配列はオブジェクトであるため、負の数や分数など、他の任意のプロパティ名を使用してプロパティを割り当てることができます。

someArray[-1] = "A property";
someArray[3.1415] = "Vaguely Pi";
someArray["test"] = "Whatever";

のような番号を指定した場合でも、舞台裏でJSはプロパティ名を文字列に変換することに注意してください-1。(正の整数インデックスも文字列になります。)

アレイ法、など.pop().slice()など、ゼロまたは、より高い整数「インデックス」ではなく、他の特性にのみ作業するのでlength、その点に一貫しています。


あなたの答えが大いに役立ってくれてありがとう。また、負のインデックスを使用してスプライスメソッドを試しましたが、-1を使用すると配列の最後の要素に移動し、-2を使用すると最後から2番目の要素に移動することがわかりました。
me_digvijay 2012年

+1。長さは、要素がいくつあるか、またはプロパティがいくつあるかを示しません。これは、最高のインデックス+1です。たとえば、与えられたvar a = new Array(9)場合a、長さは9で、要素はまったくありません。
RobG 2012年

1
@ DigvijayYadav-はい、Array.slice()メソッドはそれを行うことになっています。String.slice()この方法は、同じことを行います。
nnnnnn 2012年

7

位置(または0)インデックスを使用する場合、値は配列内に配置されることに注意してください。

var array = [];

array[0] = "Foo";
array[1] = "Bar";

// Result: ["Foo", "Bar"]
// Length: 2

これは、インデックス以外の値(0〜9 +ではない)を追加する場合には当てはまりません。

var array = [];

array[0]  = "Foo";
array[1]  = "Bar";
array[-1] = "Fizzbuzz"; // Not a proper array index - kill it

// Result: ["Foo", "Bar"]
// Length: 2

ルールに従ってプレイする場合にのみ、値が配列に配置されます。そうしないと、受け入れられません。ただし、これらはArrayオブジェクト自体で受け入れられます。これは、JavaScriptのほぼすべての場合に当てはまります。["Foo", "Bar"]配列内の唯一の値ですが、アクセスできます"Fizzbuzz"

array[-1]; // "Fizzbuzz"

ただし、「インデックス」が無効であるため、これは配列値の一部ではないことに注意してください。代わりに、別のメンバーとして配列に追加されました。同じ方法で他の配列メンバーにアクセスできます。

array["pop"]; // function pop() { [native code] }

ここではpop、配列のメソッドにアクセスしていることに注意してください。これにより、ネイティブコードが含まれていることがわかります。「pop」のキーで配列値にアクセスするのではなく、配列オブジェクト自体のメンバーにアクセスします。オブジェクトのパブリックメンバーを循環することで、これをさらに確認できます。

for (var prop in array) 
    console.log(prop, array[prop]);

これは以下を吐き出します:

 0 Foo
 1 Bar
-1 Fizzbuzz

繰り返しになりますが、これはオブジェクト上にありますが、配列内にはありません。

素晴らしい質問です!確かにダブルテイクをさせてくれました。


1
+1仕様では、正の数値のプロパティ名を持つプロパティは配列の要素と呼ばれます(他のプロパティはそうではありません):es5.github.com/#x15.4
Felix Kling 2012年

結果はそうではありません:["Foo", "Bar"]しかし、ここでフィドルを["Foo", "Bar", -1: "Fizzbuzz"]チェックしてください。あなたが書いたように、それはキー-1のプロパティになりますが、出力には間違いなく表示されます。そうでなければ、あなたの答えは素晴らしく、完全です。あなたが変更した場合、私は再び賛成します、私の反対票は厳しいものでしたが、それを取り除くことはできません。時間切れ。
ウィルト

5

本当に負のインデックスやその他のインデックスを長さに含めたい場合は、自分で機能を作成してください。

function getExtendedArray() {
    var a = [];

    Object.defineProperty(a, 'totalLength', { 
        get : function() { return Object.keys(a).length; }
    });

    return a;
}

次に、例えば:

var myArray = getExtendedArray();
console.log(myArray.totalLength); // 0
myArray.push("asdf");
myArray[-2] = "some string";
myArray[1.7777] = "other string";
console.log(myArray.totalLength); // 3

また、長さに番号付きのインデックス/プロパティのみを含める場合は、キーのifステートメントを追加できます-if(Number(key) != NaN) length++;フロートのものを&& key % 1 == 0
除外する

4

配列は、JSの特別な種類のオブジェクトです。特別な構文があります。これは、それらを効果的に操作できるため、優れています。そのように配列リテラルを書くのがどれほど退屈であるか想像してみてください。

const array = {0: 'foo', 1: 'bar', 2: 'baz'} //etc...

しかし、それでもなおオブジェクトです。だからあなたがそうするなら:

const myArray = [42, 'foo', 'bar', 'baz'];

myArray[-1] = 'I am not here';
myArray['whatever'] = 'Hello World';

これらの非整数プロパティはオブジェクト(配列)にアタッチされますが、のような一部のネイティブメソッドではアクセスできませんArray.length

ネイティブの「長さ」メソッドは、正の整数またはゼロに変換可能なすべてのプロパティ(およびインデックスプロパティであり、値は実際の)をカウントするゲッターであると想定できます。この疑似実装のようなもの:

仕様により、ネイティブlengthメソッド(ゲッターexampleArray.length)として)は、すべての「2 32未満の非負の整数」キーをチェックし、最大のものを取得して、その数値+1を返します。

セッターexampleArray.length = 42)として、指定された長さが非負の整数キーの実際の数よりも大きい場合、「欠落している」インデックス用の空のスロットを作成するか、または以下のすべての非負の整数キー(およびそれらの値)を削除します。与えられた長さ。

疑似実装:

const myArray = {
  '-1': 'I am not here', // I have to use apostrophes to avoid syntax error
  0: 42,
  1: 'foo',
  2: 'bar',
  3: 'baz',
  whatever: 'Hello World',

  get myLength() {
    let highestIndex = -1;
    for (let key in this) {
      let toInt = parseInt(key, 10);
      if (!Number.isNaN(toInt) && toInt > -1) {
        // If you're not an integer, that's not your business! Back off!
        if (toInt > highestIndex) highestIndex = toInt;
      }
    }
    return highestIndex + 1;
  },
  set myLength(newLength) {
    /* This setter would either:
      1) create some empty slots for 'missing' indices if the given length is greater than the actual number of non-negative-integer keys
      2) delete all non-negative-integer keys (and their values) which are not greater then the given length.
    */
  }
}

console.log(myArray.myLength); // 4

myArray[9] = 'foobar';

console.log(myArray.myLength); // 10


3

JavaScriptの配列は実際にはオブジェクトです。それらは、配列コンストラクターから単純にプロトタイプ化されています。

配列インデックスは実際にはハッシュマップのキーであり、すべてのキーは文字列に変換されます。任意のキー(つまり「-1」)を作成できますが、Arrayのメソッドは配列のように機能するように調整されています。したがってlength、オブジェクトのサイズではなく、最大の整数インデックスよりも大きいことが保証されているだけです。同様に、印刷でarrは整数キー> = 0の値のみが一覧表示されます。

詳細はこちら。


丁度。または、array ['foo']が有効なインデックスではない理由を疑問に思うかもしれません。javascriptではそれが可能ですが、配列(およびその要素)の定義が言語ごとに変わるわけではありません。意図したとおりに動作します。
airball TW

実際、「配列」はJSには存在しません。しかし、「オブジェクト」としても知られる「連想配列」は、JSの中核です。したがって、通常の配列を模倣するArrayオブジェクトを作成することは大きな飛躍ではありませんでした。
トニーR

1
配列とプレーンオブジェクトの間には、非常に特別な違いが1つあります。それは、自己調整型の長さプロパティです。
RobG 2012年

1

MDNによると:

長さプロパティの値は、正の符号と2の32乗(232)未満の値を持つ整数です。

Javascriptでは、作成する任意のオブジェクトにプロパティを設定できます。

var array = new Array();
array = [1,2,3];
array["boom"] = "pow";

同様に、負のインデックスを設定すると、インデックスの一部ではなく、配列のプロパティとして保存されます。

array[-1] = "property does not add to array length";

これが長さがそれを反映しない理由ですが、for..inループはそれを示します。


-1

非正または非数値のインデックスを使用すると、配列はキーと値のペアを持つ連想配列として動作します。

配列を反復処理するには、次を使用できます

for(var index in myArray) {
  document.write( index + " : " + myArray[index] + "<br />");
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.