2013-04-11 13 views
12

Piszę interpreter JavaScriptu dla ekstremalnie ograniczonych zasobów osadzonych urządzeń (http://www.espruino.com) i za każdym razem, gdy myślę, że poprawnie zaimplementowałem trochę JavaScriptu, zdaję sobie sprawę, że jestem w błędzie.Jak działa JavaScript []?

Moje pytanie dotyczy teraz []. Jak poprawnie zaimplementować jeden z najbardziej podstawowych bitów JavaScript?

Przeglądam specyfikację JavaScript i być może nie znalazłem właściwego bitu, ale nie mogę znaleźć przydatnej odpowiedzi.

Wcześniej zakładałem, że faktycznie masz dwie "mapy" - jedną dla liczb całkowitych i jedną dla łańcuchów. A długość tablicy była wartością najwyższej liczby całkowitej plus jeden. Jednak wydaje się to źle, według jsconsole na chrome:

var a = []; 
a[5] = 42; 
a["5"]; // 42 
a.length; // 6 

ale również:

var a = []; 
a["5"] = 42; 
a[5]; // 42 
a.length; // 6 

Więc ... wielki - wszystko jest przekształcony w ciąg, a najwyższym ceniony ciąg, który reprezentuje liczbę całkowitą jest używany (plus jeden), aby uzyskać długość? Źle.

var a = []; 
a["05"] = 42; 
a.length; // 0 

"05" jest prawidłową liczbą całkowitą - nawet w ośmiu. Dlaczego więc nie wpływa na długość?

Czy należy przekonwertować ciąg na liczbę całkowitą, a następnie sprawdzić, czy po konwersji z powrotem na ciąg pasuje?

Czy ktoś ma odniesienie do dokładnego algorytmu używanego do przechowywania i pobierania elementów w tablicy lub obiekcie? Wygląda na to, że powinno być bardzo proste, ale wygląda na to, że tak naprawdę nie jest!

+6

[Standard] (http://www.ecma-international.org/ecma-262/5.1/#sec-15.4) mówi: "* Nazwa właściwości' P' (w formie 'ciągu' value) jest indeksem tablicy wtedy i tylko wtedy, gdy 'ToString (ToUint32 (P))' jest równe 'P' i' ToUint32 (P) 'nie jest równe' 2 ** 32-1'. * ". – DCoder

+6

Jeśli piszesz tłumacza, nie należy używać założeń. Powinieneś czytać specyfikację. –

+0

Dlaczego nie używasz istniejących, wydajnych i zgodnych ze standardami implementacji JS, takich jak V8? To, co przeczytałem na http://www.espruino.com/Performance brzmiało okropnie: -/ – Bergi

Odpowiedz

4

W specyfikacji powiedział i obserwowano przez innych:

„nazwy właściwości P (w postaci wartości łańcuchach) jest indeksem tablicy, wtedy i tylko wtedy, gdy toString (ToUint32 (P)) jest równe P, a ToUint32 (P) nie jest równe 2^32-1. "

To wyjaśnia, dlaczego w swoim scenariuszu "5" jest uważany za wskaźnik tablicy i "05" nie jest:

console.log("5" === String("5" >>> 0)); 
// true, "5" is equal to "5", so it's an index 

console.log("05" === String("05" >>> 0)); 
// false, "05" is not equal to "5", so it's not an index 

Uwaga: Zero-fill right shift to najkrótsza droga w JS mieć namiastkę ToUint32, przeniesienie numeru do zera.

+0

Dzięki - to wyjaśnia również problem z długością tablicy, której inne odpowiedzi tak naprawdę nie rozwiązały. Dziękuję za link do specyfikacji i DCodera –

3

Tablice są po prostu obiektami. Oznacza to, że mogą mieć dodatkowe właściwości, które nie są uważane za elementy tablicy.

Jeśli argument nawias kwadratowy jest liczbą całkowitą, wykorzystuje go do wykonania przypisania do tablicy. W przeciwnym razie traktuje to jako ciąg znaków i przechowuje go jako właściwość obiektu tablicy.

Edit oparte na komentarz delnan i komentarzu DCoder, ten jest jak JavaScript określa, czy jest to odpowiedni indeks tablicy (w porównaniu do zaledwie własności): http://www.ecma-international.org/ecma-262/5.1/#sec-15.4

+0

Ostatnia część nie jest szczególnie przydatna, chyba że zdefiniujesz * co dokładnie * "jest liczbą całkowitą", a co nie jest.Na przykład, "05" jest liczbą całkowitą i dlaczego (nie)? – delnan

4

Zobacz MDN

Możliwe jest również cytowanie indeksów tablicy JavaScript (np. lat ["2"] zamiast lat [2]), chociaż nie jest to konieczne. The 2 in years [2] ostatecznie zostaje przekształcona w ciąg znaków przez silnik JavaScript , w każdym razie poprzez niejawną konwersję toString. Jest to dla tego powodu, że „2” i „02” będzie odnosić się do dwóch różnych gniazd na lata przedmiotu oraz Poniższy przykład loguje prawda:

console.log(years["2"] != years["02"]); 

Więc z a["5"] uzyskiwania dostępu do tablicy while a["05"] ustawia właściwość obiektu tablicy.

1

Tablice są również obiektami.

Robiąc to

a["05"] = 5; 

Robicie to samo, co:

a.05 = 5; 

Jednak, powyższe spowoduje błąd składni, jako właściwość określona po kropce nie może zacznij od numeru.

Więc jeśli to zrobić:

a = []; 
a["05"] = 5; 

nadal mają pustą tablicę, ale własność a nazwie 05 ma wartość 5.

Liczba xis an array index wtedy i tylko wtedy ToString(ToUint32(x)) jest równa x (tak w przypadku "05" że wymóg nie jest spełniony).