2013-04-07 10 views
6

próbuję następujący kod w ideone:Czy długość tablicy tablicowej Array.pop()?

var a = []; 
a[0] = 0; 
a[5] = 5; 
a[6] = undefined; 
print("contents before popping:"); 
for(var e in a) print("\ta[", e, "] =", a[e]); 
print("a.length =", a.length); 
for (var i = 0; i < a.length; i++) 
    print("\ta.hasOwnProperty(", i, ") =", a.hasOwnProperty(i)); 

print("popping -->", a.pop()); 
print("popping -->", a.pop()); 
print("contents after popping:"); 
for(var e in a) print("\ta[", e, "] =", a[e]); 
print("a.length =", a.length); 
for (var i = 0; i < a.length; i++) 
    print("\ta.hasOwnProperty(", i, ") =", a.hasOwnProperty(i)); 

Wyjście przechodzi w następujący sposób:

contents before popping: 
    a[ 0 ] = 0 
    a[ 5 ] = 5 
    a[ 6 ] = undefined 
a.length = 7 
    a.hasOwnProperty(0) = true 
    a.hasOwnProperty(1) = false 
    a.hasOwnProperty(2) = false 
    a.hasOwnProperty(3) = false 
    a.hasOwnProperty(4) = false 
    a.hasOwnProperty(5) = true 
    a.hasOwnProperty(6) = true 
popping --> undefined 
popping --> 5 
contents after popping: 
    a[ 0 ] = 0 
a.length = 5 
    a.hasOwnProperty(0) = true 
    a.hasOwnProperty(1) = false 
    a.hasOwnProperty(2) = false 
    a.hasOwnProperty(3) = false 
    a.hasOwnProperty(4) = false 

w mojej książce JavaScript (dobrze, Crockforda'S) Czytałem długość tej tablicy jest obliczana jako największy wartość liczbowa wszystkich właściwości. Dlaczego mówi się, że długość wynosi 5, gdy największą właściwością liczbową jest 0? Dzięki!

Odpowiedz

6

Ładny rzeczą jest to, że JavaScript jego semantyka jest formalnie i tak jednoznacznie określona w standardzie. W szczególności, section 15.4 stwierdza, że:

Wartość właściwości length jest liczbowo większa niż nazwa każdej właściwości, której nazwa jest indeksem tablicy; ilekroć własność obiektu Array jest tworzona lub zmieniana, inne właściwości są dostosowywane w razie potrzeby w celu zachowania tego niezmiennika.

Innymi słowy, za każdym razem zmienić tablicę, jej length ulega zmianie, jednak to zagwarantowane tylko być większa niż max(indexes) i niekoniecznie równa max(indexes)+1. Na przykład pop method zawsze usuwa element "length-1" i dekoduje length o jeden, niezależnie od tego, ile elementów zawiera tablica.

Należy również zwrócić uwagę, że większość metod tablicowych ma charakter ogólny i nie "w ogóle" nic nie mówi o tablicach. Mogą manipulować dowolnymi obiektami, a jeśli taki obiekt ma właściwość o nazwie length, zostanie dostosowany zgodnie z powyższą zasadą. Rozważmy:

foo = { 
    length: 100, 
    99: 'hi' 
} 

alert([].pop.apply(foo)) // hi 
alert(foo.length)  // 99 

alert([].pop.apply(foo)) // undefined 
alert(foo.length)  // 98 

Oznacza to, że w tym kontekście pytanie jest bez znaczenia, jak dokładnie tablice są reprezentowane - pop i przyjaciele nie korzystać z tej informacji.

+0

Przekazywałem to skrzypce, aby pokazać, kiedy Array.length jest niewiarygodna, oprócz twojego przykładu. http://jsfiddle.net/6WrkT/1/ –

1

przycisków „problemem” jest przypisanie z 5.

W drugiej kolejności tablica JavaScript zostaje wypełniona gniazdami, które zostają zainicjowane wartością undefined.

Więc wywołanie

a[5] = 5; 

powoduje

[0, undefined, undefined, undefined, undefined, 5] 

Następnie należy utworzyć również a[6] i zainicjować go undefined i otrzymujemy

[0, undefined, undefined, undefined, undefined, 5, undefined] 

.length z 7.

Teraz nazywamy podwójne.pop() (uwielbiam doublepop słowo) i otrzymujemy

[0, undefined, undefined, undefined, undefined] 

.length z


Faktycznie, jak wskazano w komentarzach, to nadal wydaje się być bardzo dziwnym zachowaniem. Podczas inicjowania dowolnego indeksu, miejsca wcześniej nie są w rzeczywistości przypisane. Tworzy on rzadką macierz . Ale znowu, jeśli usuniemy dwa ostatnie wpisy, pozostała tylko jedna wartość (0), a następnie undefined wartości (które w jakiś sposób stały się wartościami prawdziwe, prawdopodobnie dlatego, że ręcznie przypisaliśmy 6).

Chyba musimy guru realizacji :)

+2

Tablica nie zostanie wypełniona, ponieważ 'hasOwnProperty' zwraca' fałsz' –

+0

Nie jestem pewien, czy wartości pośrednie są zainicjowane na 'niezdefiniowane', raczej myślę, że' a' jest rzadką tablicą. – lmsteffan

+0

@lmsteffan, masz rację, teraz jestem zdezorientowany. Wygląda na to, że mój opis pasuje, ale w rzeczywistości nie powinno być już wolnych miejsc. – jAndy

0

Problem jest rzeczywiście związane z faktem, że nie są z wykorzystaniem indeksów sekwencyjnych zamiast na fakt, że używasz funkcji pop. Zauważycie, że na pierwszym wydruku długości długość tablicy wynosi 7, ale macie w niej tylko 3 przedmioty. Jest to związane z tym, że długość zwraca maksymalny indeks/właściwość (+1), ponieważ pozostałe wartości są ustawione jako niezdefiniowane wartości.

Czy naprawdę potrzebujesz indeksów niesekwencyjnych?Jeśli tak, możesz spróbować użyć:

var counter = 0; 
for (var i in a) { 
    counter++; 
    print("Property: "+i); 
} 
print("Total items: "+counter); 

Ale to daleki od optymalności, wydajności.

+0

Witam, nie mam żadnych problemów z kodem. Jest to czysty sztuczny konstrukt, ponieważ próbuję jedynie zrozumieć język. Szukam wyjaśnienia, dlaczego działa w ten sposób, a nie jak to naprawić. –

+0

Mam cię. Wtedy musiałbym zgodzić się z powyższą odpowiedzią, chociaż nie jestem pewien, czy to samo zachowanie jest takie samo we wszystkich przeglądarkach. – sagibb

1

„długość tablicy jest obliczana jako największej wartości liczbowej wszystkich właściwości ”

to nie jest odpowiednia dla wszystkich zastosowań tablicy. Działa to w ten sposób, jeśli przypiszesz wartość do indeksu w tablicy, ale nie, jeśli ustawisz konkretnie lub użyjesz metod takich jak pop.

Przykład:

var a = []; 
a.length = 5; 

console.log("length =", a.length); 

for (var i = 0; i < a.length; i++) 
    console.log("a.hasOwnProperty(", i, ") =", a.hasOwnProperty(i)); 

wyjściowa:

length = 5 
a.hasOwnProperty(0) = false 
a.hasOwnProperty(1) = false 
a.hasOwnProperty(2) = false 
a.hasOwnProperty(3) = false 
a.hasOwnProperty(4) = false 

Teraz masz tablicę bez żadnych elementów w niej, ale długość wynosi 5.

+0

ale pozostaje pytanie, dlaczego i gdzie stają się gniazda '1 ... 4' * prawdziwe * gniazda z wartością' niezdefiniowaną'? Właściwie jak @lamsteffan wskazał poprawnie, mamy do czynienia tylko z rzadką tablicą. – jAndy

+0

@jAndy Guffa ma rację. 'Array.splice' i bezpośrednie przypisanie' length' wykazują to samo zachowanie, a powodem wydaje się być to, że 'length' zostaje w pewnym momencie przypisany. –

+0

@jAndy: Nieużywane gniazda nie mają żadnych wartości, ale jeśli spróbujesz odczytać z boksa, który nie istnieje, otrzymasz 'undefined' z powrotem. Na przykład 'console.log ([] [42]);' wyświetla 'undefined'. – Guffa

Powiązane problemy