2012-02-07 24 views
6

Próbowałem splajtować obiekt podobny do tablicy, który został zadeklarowany jako obiekt tablicy i okazało się, że JSON.stringify nie przetwarzał poprawnie obiektu podobnego do tablicy, gdy jest zdefiniowany jako obiekt tablicy.JavaScript Array Object vs Array Like Objects - Clarification

Poniżej większej jasności, ->jsFiddle

var simpleArray = []; //note that it is defined as Array Object 

alert(typeof simpleArray); // returns object -> Array Object 

simpleArray ['test1'] = 'test 1'; 
simpleArray ['test2'] = 'test 2'; 

alert(JSON.stringify(simpleArray)); //returns [] 

to działało dobrze i wrócił do mnie {"test1":"test 1","test2":"test 2"} kiedy zmienił

var simpleArray = []; do var simpleArray = {};.

Czy ktoś może rzucić trochę światła lub jakieś odniesienie, gdzie mogę przeczytać więcej?

Edit:

Pytanie: Kiedy typeof simpleArray = [] i simpleArray = {} zwrócony obiekt, dlaczego JSON.stringify nie był w stanie wrócić {"test1":"test 1","test2":"test 2"} w obu przypadkach?

Odpowiedz

2

Nie chcesz tablicy. Gdy chcesz mieć "tablicę asocjacyjną" w JavaScript, naprawdę potrzebujesz obiektu, {}.

można odróżnić je instanceof Array:

[] instanceof Array // true 
({}) instanceof Array // false 

EDIT: to może go przetworzyć. Serializuje wszystkie elementy tablicy. Jednak aby być elementem, musi istnieć klucz numeryczny. W tym przypadku nie ma żadnych.

To nic wyjątkowego dla JSON. Jest to zgodne z właściwością toSource i length.

+0

Rozumiem tę część, co chciałem wiedzieć, dlaczego JSON.stringify nie może przetwarzać, gdy zostanie zadeklarowany jako []. –

+0

Dziękujemy !. Szukałem instanceof. Próbowałem użyć typeof, który zwracał obiekt w obu przypadkach. –

+1

Od wersji ES 5 jest także 'Array.isArray (...)' (15.4.3.2), która z kolei jest bezpieczna dla ramki. Można go emulować. – PointedEars

4

Różnica polega na indeksach. Gdy używasz tablicy [] indeksy mogą być tylko dodatnimi liczbami całkowitymi.

Więc dodaje się źle:

var array = [ ]; 
array['test1'] = 'test 1'; 
array['test2'] = 'test 2'; 

ponieważ test1 i test2 nie są liczbami całkowitymi. Aby to naprawić trzeba użyć indeksów opartych integer:

var array = [ ]; 
array[0] = 'test 1'; 
array[1] = 'test 2'; 

lub jeśli zadeklarować JavaScript Object potem właściwości mogą być dowolne ciągi:

var array = { }; 
array['test1'] = 'test 1'; 
array['test2'] = 'test 2'; 

co jest równoważne:

var array = { }; 
array.test1 = 'test 1'; 
array.test2 = 'test 2'; 
+0

Co się dzieje, gdy wykonasz 'var simpleArray = []; simpleArray ['test2'] = 'test 2'; '? –

+3

@MattFenwick, co się dzieje w przeciwieństwie do tego, czego można się spodziewać: 'simpleArray.length = 0', co oznacza, że ​​w tej tablicy nie ma elementów. Nadal można użyć 'simpleArray.test2', aby uzyskać dostęp do zdefiniowanej właściwości. To po prostu mylący kod, którego należy unikać. –

+0

+1 za szczegółowe wyjaśnienie, ale chciałem się dowiedzieć, dlaczego JSON.stringify nie może przetworzyć, gdy zostanie zadeklarowane jako []. Próbowałem użyć typeof i zwrócił mi obiekt w obu przypadkach. Zamierzam dodać to do mojego pytania. –

1

Gdy JSON.stringify napotka tablicy, iteracje w sposób podobny do pętli z 0for do simpleArray.length znaleźć wartości. Na przykład:

var a = []; 
a[5] = "abc"; 
alert(JSON.stringify(a)); // alerts [null,null,null,null,null,"abc"] 

właściwości Dlatego ustawienie na nim będzie całkowicie niewidoczny dla JSON.

Jednak zdefiniowanie obiektu za pomocą {} powoduje, że JSON traktuje go jako obiekt, a zatem pętle nad właściwościami obiektu (z wyłączeniem dziedziczonych właściwości z łańcucha prototypów). W ten sposób może znaleźć twoje właściwości test1 i test2 i pomyślnie zwraca to, czego oczekujesz.

2

"Czy ktoś może rzucić trochę światła lub jakieś odniesienie, gdzie mogę przeczytać więcej?"

Kiedy masz do czynienia z JSON danych, można zwrócić się do json.org do zapoznania się z wymaganiami specyfikacji.

W JSON, Array jest listą zleceń z wartościami oddzielonymi przez ,.

enter image description here

Więc JSON.stringify() jest po prostu ignorując wszystko, co nie może być reprezentowany jako proste listy uporządkowanej.

Więc jeśli nie ...

var simpleArray = []; 
simpleArray.foo = 'bar'; 

... nadal jesteś dając tablicy, więc spodziewa się tylko indeksy numeryczne, a ignorowanie czegokolwiek innego.

Ponieważ JSON jest językiem niezależnym, metody pracy z JSON muszą podjąć decyzję o tym, która struktura językowa najlepiej pasuje do każdej struktury JSON.

Więc JSON ma następujące struktury ...

{} // object 
[] // array 

Należy pamiętać, że chociaż wyglądają bardzo podobnie do JavaScript obiektów i tablic, nie są one ściśle takie same.

Wszelkie struktury JavaScript użyte do stworzenia konstrukcji muszą być zgodne z tym, co dopuszczą struktury JSON. Właśnie dlatego wykluczono właściwości nieliczbowe.

Podczas gdy JavaScript nie ma nic przeciwko temu, JSON nie będzie ich tolerować.

+0

Właściwości nieliczbowe (lepsze: właściwości z nieliczbową * nazwą *) nie są usuwane.W pierwszej kolejności nie są one brane pod uwagę przy iteracji. – PointedEars

+0

@ PointedEars: To było słabe sformułowanie. Chodziło mi o usunięcie z perspektywy dewelopera, jak w * "Hej, oni są w moim obiekcie Array, ale nie w moim tekście JSON!" *. Powinienem był powiedzieć "wykluczony" *. –

-1

Twój kod nie jest semantycznie poprawny, ale ponieważ większość silników JavaScript jest naprawdę miłych dla programisty, dopuszczają one następujące typy błędów: .

Szybkie przypadek testowy:

var a = []; 
a.b = "c"; 
console.log(JSON.stringify(a));//yields [], and not {"b":"c"} as you might expect 

Może to być spowodowane jakimś surowości w JSON.stringify które nadal traktuje a jak Array. Nie martwiłbym się tym zbytnio. Jest to sytuacja, która nie powinna wystąpić w twoim programie, ponieważ jest to błąd. JSLint to popularne narzędzie do wychwycenia tych i wielu innych potencjalnych problemów w kodzie.

+0

Módl się, co jest nie tak z * składnią *? – PointedEars

+0

Myślałem, że było to dość oczywiste: nie można zadeklarować kluczy ciągów w 'tablicach'. Tylko dlatego, że większość silników JavaScript akceptuje, to nie czyni go _oryginalnym_. Mam nadzieję, że uważacie, że głosowanie w dół jest tego warte. – Halcyon

+0

Masz poważne nieporozumienia co do natury JavaScriptu, obiektów ECMAScript i tego, co należy do składni języka programowania. Jedna uwaga jest krótka. * Nie ma kluczy. * Obiekty mają * właściwości * z nazwami. Nazwy właściwości to * ciągi *, dostępne za pomocą '[' ... ']', '.' lub niejawnie (łańcuch zasięgu). JavaScript jest implementacją ECMAScript. * JavaScript * istnieją tylko dwie "jakościowe" implementacje: SpiderMonkey i Rhino; inne, takie jak JScript, to implementacje * ECMAScript *. Ciąg dalszy nastąpi ... – PointedEars

0

W JavaScript wszystko jest przedmiotem, więc nawet tablice. To dlatego masz:

>> var l = [1, 2]; 
>> typeof l 
"object" 

Tablice są przechowywane tak samo jak obiekty. Tak więc, tablice są tylko obiektami możliwymi do hartowania. Indeks podany podczas uzyskiwania dostępu, na przykład

>> l[0] 

nie jest interpretowany jako offset, ale jest mieszany, a następnie wyszukiwany.

Array, to po prostu obiekty (z niektórymi wbudowanymi metodami tablicowymi), dzięki czemu można traktować je jak obiekty i umieszczać wartości pod określonym kluczem. Ale tylko te klucze indeksowane według liczb są używane do obliczenia długości.

>> var l = [] 
>> l.length 
0 
>> l[5] = 1; 
>> l.length 
6 
>> l 
[undefined, undefined, undefined, undefined, undefined, 1] 
>> l.hello = "Hello" 
>> l.length 
6 

Czytaj Array - MDN więcej informacji i Associative Arrays considered harmful dlaczego nie powinno się tego robić.

+0

Not * everything * to obiekt. Są prymitywne wartości. Ale nie ma "Javascript", istnieje kilka różnych implementacji ECMAScript. – PointedEars

1

Różnice między instancjami Array i innymi obiektami określono w sekcji ECMAScript Language Specification, Edition 5.1, sekcja 15.4.

Znajdziecie tam że jednocześnie można używać składni właściwość dostępowej wspornika wszelkich odniesień Object -

objRef[propertyName] 

- Array przypadki są wyjątkowe. Tylko użycie wartości parametru, której reprezentacja ciągów jest niepodpisana, 32-bitowa liczba całkowita mniejsza niż 2 -1 uzyskuje dostęp do elementu z enkapsulowanej struktury tablicowej, a dostęp do zapisu wpływa na wartość właściwości instancji instancji.

Sekcja 15.12 określa odpowiednio obiekt JSON i jego metodę stringify.