Dlaczego mogę dodać nazwane właściwości do tablicy tak, jakby to był obiekt?

105

Poniższe dwa różne fragmenty kodu wydają mi się równoważne:

var myArray = Array();
myArray['A'] = "Athens";
myArray['B'] = "Berlin";

i

var myObject = {'A': 'Athens', 'B':'Berlin'};

ponieważ oboje zachowują się tak samo, a także typeof(myArray) == typeof(myObjects)(obie dają „przedmiot”).

Czy jest jakaś różnica między tymi wariantami?

prinzdezibel
źródło

Odpowiedzi:

131

Praktycznie wszystko w javascript jest obiektem, więc możesz „nadużywać” obiektu Array , ustawiając na nim dowolne właściwości. To powinno być uważane za szkodliwe chociaż. Tablice są przeznaczone dla danych indeksowanych numerycznie - w przypadku kluczy nienumerycznych użyj Object.

Oto bardziej konkretny przykład, dlaczego klucze nienumeryczne nie „pasują” do tablicy:

var myArray = Array();
myArray['A'] = "Athens";
myArray['B'] = "Berlin";

alert(myArray.length);

To nie wyświetli „2”, ale „0” - w rzeczywistości żadne elementy nie zostały dodane do tablicy, tylko kilka nowych właściwości dodanych do obiektu tablicy.

Paul Dixon
źródło
4
myArray.length zwraca numeryczny indeks / klucz ostatniego elementu tablicy, ale nie zwraca rzeczywistej liczby elementów. Czy właściwości obiektu Array nie są tym samym, co wartości tablicy?
Dasha Salo
1
Próbowałem tylko zilustrować zamierzoną semantykę obiektu Array, która jest nadużywana, jeśli po prostu traktujesz go jak zwykły obiekt. Jednak linkowany artykuł działa lepiej :)
Paul Dixon
13
Następnym razem, gdy ktoś powie, że JavaScript jest dobrym językiem do programowania, pokażę mu ten przykład. Dziękuję Ci.
Olivier Pons
@Olivier, to, co nazywasz „błędem”, może równie dobrze być niesamowitą „funkcją”. Można dodać kreska i opis do tablic bez wpływu na ich zawartość lub długość i bez konieczności owinąć je w obiektach z title, descriptioni itemswłaściwości. Wszystko zależy od tego, jak dobrze znasz język i jak go używasz.
tao
Używanie niestandardowych właściwości w tablicach nie jest z natury złe. Co jest nie tak, to oczekiwanie, że gdy to zrobisz, będą działać jako członkowie tablicy. Są to właściwości tablicy, a nie elementy składowe, dlatego metody tablicowe nie mają na nie wpływu. Faktycznie jest to powiedziane przez autora wyżej wymienionego artykułu w komentarzach. Teraz, szczerze mówiąc, odradzałbym to jako praktykę, ponieważ prawdopodobnie zmyliłoby to ludzi używających twojego kodu. Lub, jeśli dopiero zaczynają, skieruje ich to na niebezpieczną ścieżkę siłą przykładu. Ale nie powiedziałbym, że JavaScript jest zły, ponieważ pozwala na rzeczy, których większość nie oczekuje.
tao
14

W JS tablice są obiektami, tylko nieznacznie zmodyfikowanymi (z kilkoma dodatkowymi funkcjami).

Funkcje takie jak:

concat
every   
filer
forEach
join
indexOf
lastIndexOf
map
pop
push
reverse
shift
slice
some
sort
splice
toSource
toString
unshift
valueOf 
Casey
źródło
Chociaż nie sądzę, aby wszystkie wymienione funkcje były wbudowane w każdą implementację JS, o co chodzi. Inną różnicą byłby inny prototyp (co wynika z tych dodatkowych funkcji).
Rashack
6

Myślę, że ja też jestem metaforyczny i tajemniczy z poprzednią odpowiedzią. Następuje wyjaśnienie.

Instancja Array, Boolean, Date, Function, Number, RegExp, String to obiekt, ale wzbogacony o metody i właściwości specyficzne dla każdego typu. Na przykład tablica ma predefiniowaną lengthwłaściwość, a obiekty ogólne nie.

javascript:alert([].length+'\n'+{}.length)

wyświetlacze

0
nieokreślony

W istocie interpreter FF Gecko rozróżnia również tablice i obiekty ogólne z wyraźnymi różnicami oceniającymi konstrukcje językowe.

javascript:
  ra=[  "one",   "two",   "three"]; ra.a=4;
  ob={0:"one", 1:"two", 2:"three"}; ob.a=4;
  alert(
    ra            +"\n\n"+
    ob            +"\n\n"+
    ra.toSource() +"\n\n"+
    ra.a          +"\t .toSource() forgot me! \n\n"+
    ra.length     +"\t and my length! \n\n"+
    ob.toSource());
  ps=""; for(i in ra)ps+=i+" "; alert(ps);  /* NB .length is missing! */
  ps=""; for(i in ob)ps+=i+" "; alert(ps);

wyświetlanie

raz Dwa Trzy

[obiekt Obiekt]

["raz Dwa Trzy"]

4 .toSource () zapomniał mnie! 

3 i moja długość! 

({0: "jeden", 1: "dwa", 2: "trzy", a: 4})

i 0 1 2 ai 0 1 2 a.

Odnośnie stwierdzenia, że ​​wszystkie obiekty są funkcjami:

Nie jest ani składniowo, ani semantycznie poprawne użycie dowolnej instancji obiektu jako funkcji takiej jak 123()lub "abc"()lub []()lub {}()lub obj()gdzie objjest dowolny typ inny niż Function, więc dowolny obiekt INSTANCE nie jest Function. Jednak biorąc pod uwagę obiekt obji jego typ jako Array, Boolean, Date, ..., jak to się objstało Array, Boolean, Date, ...? Co to jest Array, Boolean, Date, ...?

javascript:
    alert([Array, Boolean, Date, Function, 
              Number, Object, RegExp, String] . join('\n\n') );

wyświetlacze

function Array() {
    [native code]
}

function Boolean() {
    [native code]
}

function Date() {
    [native code]
}

function Function() {
    [native code]
}

function Number() {
    [native code]
}

function Object() {
    [native code]
}

function RegExp() {
    [native code]
}

function String() {
    [native code]
}

W każdym przypadku, bez dwuznaczności, typ obiektu manifestuje się jako functiondefinicja, stąd stwierdzenie, że wszystkie obiekty są funkcjami! (To żart w tym, że celowo zasłoniłem i zamazałem rozróżnienie między instancją obiektu a jej typem! Jednak to pokazuje, że „nie możesz mieć jednego bez drugiego”, obiekt i funkcja! Wielkie litery podkreślają typ jako w przeciwieństwie do instancji.)

Wydaje się, że zarówno paradygmat funkcjonalny, jak i obiektowy mają fundamentalne znaczenie dla programowania i implementacji wbudowanych prymitywów niskiego poziomu interpretera JS, takich jak Mathi JSONi true.

 javascript:alert([Math, JSON, true.toSource()].join("\n\n"));

wyświetlacze

[object Math]

[object JSON]

(new Boolean(true))

W czasie rozwoju Javascript, modny był obiektowy styl programowania (OOP - Object Oriented Programming style - „s” to moja własna gra słów!). . Funkcjonalne techniki programowania zostały zdegradowane do bardziej abstrakcyjnych i ezoterycznych egzaminów studiujących teorie automatów, funkcji rekurencyjnych, języków formalnych itp. I jako takie nie są tak smaczne. Jednak mocne strony tych formalnych rozważań są wyraźnie widoczne w Javascript, szczególnie w przypadku zaimplementowania w silniku FF Gecko (tj. .toSource()).


Definicja obiektu dla funkcji jest szczególnie satysfakcjonująca, ponieważ jest zdefiniowana jako relacja powtarzania! zdefiniowane za pomocą własnej definicji!

function Function() { [native code] }
a ponieważ funkcja jest obiektem, ten sam sentyment dotyczy
function Object() { [native code] }.

Większość innych definicji wygasa do statycznej wartości końcowej. Jednak eval()jest szczególnie potężnym prymitywem, więc String może również osadzać dowolną funkcjonalność.

Zwróć uwagę, że język używany powyżej przesłania typ obiektu i rozróżnienie instancji.

Ekim
źródło
5

Wszystko w JavaScript jest obiektem oprócz typów pierwotnych.

Kod

var myArray = Array();

tworzy wystąpienie obiektu Array while

var myObject = {'A': 'Athens', 'B':'Berlin'};

tworzy instancję obiektu Object.

Wypróbuj poniższy kod

alert(myArray.constructor)
alert(myObject.constructor)

Więc zobaczysz różnicę w typie konstruktora obiektów.

Instancja obiektu Array będzie zawierać wszystkie właściwości i metody prototypu Array.

Dasha Salo
źródło
2

Różnica między tablicami a innymi obiektami w JavaScript. Chociaż tablice mają magicznie aktualizowaną właściwość length, dla obiektów innych niż tablice nie ma możliwości zaimplementowania takiej właściwości.

var arrName = [];
arrName[5] = "test";
arrName.length; // <- 6

Tablice są używane do przechowywania rzeczy z indeksem porządkowym - używaj go jak tradycyjnej tablicy, stosu lub kolejki. Obiekt jest hashem - użyj go dla danych, które mają odrębny klucz.

Parth Raval
źródło
2

Możesz dodać nazwane właściwości do prawie wszystkiego w javascript, ale to nie znaczy, że powinieneś. Arrayw javascript powinno być używane jako lista, jeśli chcesz Objectzamiast tego użyć tablicy asocjacyjnej .

Uważaj, jeśli naprawdę chcesz użyć elementu Arrayz nazwanymi właściwościami zamiast Objecttych właściwości, nie będzie on dostępny w for...ofpętli i możesz również otrzymać nieoczekiwane wyniki, gdy zakodujesz go w formacie JSON, aby go przekazać. Patrz poniższy przykład, gdzie wszystkie non-liczbowe indeksy ignorowane:

let arr = [];
let obj = {};

arr['name'] = 'John';
obj['name'] = 'John';

console.log(arr);    // will output [name: "John"]
console.log(obj);    // will output {name: "John"}

JSON.stringify(arr); // will return [] <- not what you expected
JSON.stringify(obj); // will return {"name":"John"}
resu
źródło
-1

{}-Notation jest tylko cukier syntaktyczny aby ładniejszy kodu ;-)

JavaScript ma wiele podobnych konstrukcji, takich jak konstrukcja funkcji, gdzie function () jest po prostu synonimem

var Func = new Function("<params>", "<code>");
Dario
źródło
3
Konstruktor funkcji NIE jest synonimem literału funkcji. Literał ma zasięg leksykalny, podczas gdy konstruktor jest globalny. {}to dosłowna notacja obiektu, []to dosłowna tablica, nie jestem pewien, jaki jest sens twojej odpowiedzi.
Juan Mendes,
Ponadto zadeklarowane funkcje są dostępne przed wykonaniem jakiegokolwiek kodu, przypisania przy użyciu konstruktora funkcji nie są dostępne, dopóki kod, który je utworzy, nie zostanie wykonany.
RobG,