Zauważyłem to w Firefox-3.5.7 / Firebug-1.5.3 i Firefox-3.6.16 / Firebug-1.6.2
Kiedy odpalam Firebug:
var x = new Array(3)
console.log(x)
// [undefined, undefined, undefined]
var y = [undefined, undefined, undefined]
console.log(y)
// [undefined, undefined, undefined]
console.log( x.constructor == y.constructor) // true
console.log(
x.map(function() { return 0; })
)
// [undefined, undefined, undefined]
console.log(
y.map(function() { return 0; })
)
// [0, 0, 0]
Co tu się dzieje? Czy to błąd, czy nie rozumiem, jak go używać new Array(3)
?
javascript
arrays
map-function
szaleństwo
źródło
źródło
var y = x.map(function(){return 0; });
, i otrzymuję to zarówno dla nowej metody Array (), jak i literału tablicowego. Testowałem w Firefox 4 i Chrome.Odpowiedzi:
Wygląda na to, że pierwszy przykład
Tworzy tablicę z niezdefiniowanymi wskaźnikami.
A drugi tworzy tablicę ze wskaźnikami do 3 niezdefiniowanych obiektów, w tym przypadku wskaźniki NIE są niezdefiniowane, tylko obiekty, na które wskazują.
Ponieważ mapa jest uruchamiana w kontekście obiektów w tablicy, uważam, że pierwsza mapa w ogóle nie uruchamia funkcji, podczas gdy druga zarządza uruchomieniem.
źródło
map
wywołuje podaną funkcję wywołania zwrotnego raz dla każdego elementu w tablicy, w kolejności, i konstruuje nową tablicę z wyników.callback
Jest wywoływany tylko dla indeksów tablicy, którym przypisano wartości ; nie jest wywoływany dla indeksów, które zostały usunięte lub którym nigdy nie przypisano wartości. ” W tym przypadkux
wartościom nie przypisano wyraźnie wartości, natomiast wartościomy
przypisano, nawet jeśli była to wartośćundefined
.(new Array(1))[0] === [undefined][0]
.hasOwnProperty
chyba żehasOwnProperty
sam ma błąd:(new Array(1)).hasOwnProperty(0) === false
i[undefined].hasOwnProperty(0) === true
. W rzeczywistości możesz zrobić dokładnie to samo zin
:0 in [undefined] === true
i0 in new Array(0) === false
.x = new Array(3);
jest równoważnex = [,,,];
, niex = [undefined, undefined, undefined]
.Miałem zadanie, które znałem tylko długość tablicy i potrzebowałem przekształcić przedmioty. Chciałem zrobić coś takiego:
Aby szybko utworzyć taką tablicę:
Ale to nie zadziałało, ponieważ: (patrz odpowiedź Jonathana Lonowskiego kilka odpowiedzi powyżej)
Rozwiązaniem może być wypełnienie elementów tablicy dowolną wartością (nawet niezdefiniowaną) za pomocą Array.prototype.fill ()
Pokaż fragment kodu
Aktualizacja
Innym rozwiązaniem może być:
źródło
undefined
w.fill()
metodzie, bardzo upraszczając kod dolet arr = new Array(10).fill().map((val,idx) => idx);
Array.from(Array(10))
Z ES6 możesz to zrobić
[...Array(10)].map((a, b) => a)
szybko i łatwo!źródło
new Array(10).fill()
. Taki sam wynik jak[...Array(10)]
[...Array(10).keys()]
Rozwiązanie ES6:
Jednak nie działa na maszynopisie (2.3)
źródło
Array(10).fill("").map( ...
jest to, co zadziałało dla mnie z Typescript 2.9Tablice są różne. Różnica polega na tym, że
new Array(3)
tworzy tablicę o długości trzech, ale bez właściwości, a[undefined, undefined, undefined]
tworzy tablicę o długości trzech i trzech właściwości zwanych „0”, „1” i „2”, z których każda ma wartośćundefined
. Różnicę możesz zobaczyć za pomocąin
operatora:Wynika to z nieco mylącego faktu, że jeśli spróbujesz uzyskać wartość nieistniejącej właściwości dowolnego obiektu macierzystego w JavaScript, zwraca
undefined
(zamiast zgłaszania błędu, jak to się dzieje, gdy próbujesz odwołać się do nieistniejącej zmiennej ), co jest tym samym, co otrzymasz, jeśli właściwość została wcześniej jawnie ustawiona naundefined
.źródło
Ze strony MDC dla
map
:[undefined]
faktycznie stosuje seter do indeksu (ów) tak,map
aby iterował, podczas gdynew Array(1)
po prostu inicjuje indeksy z wartością domyślną,undefined
więcmap
pomija je.Uważam, że to samo dotyczy wszystkich metod iteracji .
źródło
W specyfikacji ECMAScript 6. edycja.
new Array(3)
definiuj tylko właściwościlength
i nie definiuj właściwości indeksu, takich jak{length: 3}
. patrz https://www.ecma-international.org/ecma-262/6.0/index.html#sec-array-len Krok 9.[undefined, undefined, undefined]
zdefiniuje właściwości indeksu i właściwości długości, takie jak{0: undefined, 1: undefined, 2: undefined, length: 3}
. patrz https://www.ecma-international.org/ecma-262/6.0/index.html#sec-runtime-semantics-arrayaccumulationElementList
Krok 5.Metody
map
,every
,some
,forEach
,slice
,reduce
,reduceRight
,filter
Array będzie sprawdzić właściwość Indeks wedługHasProperty
metody wewnętrznych, więcnew Array(3).map(v => 1)
nie będzie powoływać się na zwrotnego.Aby uzyskać więcej informacji, zobacz https://www.ecma-international.org/ecma-262/6.0/index.html#sec-array.prototype.map
Jak naprawić?
źródło
Myślę, że najlepszym sposobem na wyjaśnienie tego jest spojrzenie na sposób, w jaki Chrome to obsługuje.
Tak naprawdę dzieje się tak, że nowa funkcja Array () zwraca pustą tablicę o długości 3, ale bez wartości. Dlatego po uruchomieniu
x.map
na technicznie pustą tablicę, nie ma nic do ustawienia.Firefox po prostu „wypełnia” te puste miejsca,
undefined
nawet jeśli nie ma żadnych wartości.Nie sądzę, że jest to wyraźny błąd, tylko zły sposób na przedstawienie tego, co się dzieje. Podejrzewam, że Chrome jest „bardziej poprawny”, ponieważ pokazuje, że tak naprawdę nic nie ma w tablicy.
źródło
Właśnie na to wpadłem. Byłoby z pewnością wygodne w użyciu
Array(n).map
.Array(3)
daje z grubsza{length: 3}
[undefined, undefined, undefined]
Tworzy numerowane właściwości:{0: undefined, 1: undefined, 2: undefined, length: 3}
.Implementacja map () działa tylko na zdefiniowanych właściwościach.
źródło
To nie błąd. Tak definiuje się konstruktor Array do działania.
Z MDC:
.map()
Sposób obejmuje tylko iteracji elementy tablicy, które zostały wyraźnie miały wartości przypisane. Nawet wyraźne przypisanieundefined
spowoduje, że wartość zostanie uznana za kwalifikującą się do włączenia do iteracji. To wydaje się dziwne, ale zasadniczo jest to różnica między jawnąundefined
właściwością obiektu a brakującą właściwością:Obiekt
x
nie ma właściwości o nazwie „z”, a obiekty
ma. Jednak w obu przypadkach wydaje się, że „wartością” właściwości jestundefined
. W tablicy sytuacja jest podobna: wartośćlength
niejawnie wykonuje przypisanie wartości do wszystkich elementów od zera dolength - 1
. Dlatego.map()
funkcja nic nie zrobi (nie wywoła wywołania zwrotnego), gdy zostanie wywołana na nowo zbudowanej tablicy za pomocą konstruktora Array i argumentu numerycznego.źródło
undefined
na zawsze?x = []
zamiastx = new Array()
Jeśli robisz to w celu łatwego wypełnienia tablicy wartościami, nie możesz użyć wypełnienia ze względu na obsługę przeglądarki i naprawdę nie chcesz robić pętli for, możesz również zrobić to,
x = new Array(3).join(".").split(".").map(...
co da ci tablicę pustych smyczki.Muszę powiedzieć, że jest to dość brzydkie, ale przynajmniej problem i intencje są dość jasno przedstawione.
źródło
Ponieważ pytanie brzmi dlaczego, ma to związek z tym, jak zaprojektowano JS.
Istnieją dwa główne powody, dla których mogę wyjaśnić to zachowanie:
Wydajność: Biorąc pod uwagę
x = 10000
inew Array(x)
rozsądne jest, aby konstruktor unikał zapętlania od 0 do 10000 w celu wypełnienia tablicyundefined
wartościami.Domniemane „niezdefiniowane”: Podaj
a = [undefined, undefined]
ib = new Array(2)
,a[1]
ib[1]
oba powrócąundefined
, alea[8]
ib[8]
powrócą,undefined
nawet jeśli będą poza zasięgiem.Ostatecznie notacja
empty x 3
jest skrótem, aby uniknąć ustawiania i wyświetlania długiej listyundefined
wartości, które iundefined
tak są, ponieważ nie są one jawnie zadeklarowane.Uwaga: Ze względu tablica
a = [0]
ia[9] = 9
,console.log(a)
powróci(10) [0, empty x 8, 9]
, wypełniając lukę automatycznie poprzez zwrot różnicy między dwiema wartościami zadeklarowane jawnie.źródło
Z powodów dokładnie wyjaśnionych w innych odpowiedziach
Array(n).map
nie działa. Jednak w ES2015Array.from
akceptuje funkcję mapy:źródło
Oto prosta metoda narzędzia jako obejście:
Prosta mapa
Kompletny przykład
Oto bardziej kompletny przykład (z kontrolą poprawności), który pozwala również określić opcjonalny indeks początkowy:
Odliczać
Manipulowanie indeksem przekazywanym do wywołania zwrotnego pozwala na liczenie wstecz:
źródło