Jak sprawdzić, czy zmienna jest tablicą w JavaScript? [duplikować]

Chciałbym sprawdzić, czy zmienna jest tablicą lub pojedynczą wartością w JavaScript.

Znalazłem możliwe rozwiązanie...

if (variable.constructor == Array)...

Czy to najlepszy sposób, w jaki można to zrobić?


person Andy McCluggage    schedule 20.04.2009    source źródło
comment
Sprawdzanie, czy obiekt ma być tablicą, ma pewne szczególne zastrzeżenia... Odpowiedź Piotra jest jedyną, której powinieneś użyć.   -  person aleemb    schedule 20.04.2009
comment
@Andy Wygląda na to, że moja odpowiedź nie jest najlepsza. Może powinieneś wybrać inną odpowiedź jako zaakceptowaną?   -  person Peter Smit    schedule 07.08.2011
comment
Dobra uwaga Piotrze. Nie zdawałem sobie sprawy, że twoja odpowiedź to takie komentarze. Myślę, że już dawno zacząłem używać funkcji JQuery.isArray podczas sprawdzania tablic i co ciekawe, jest ona zaimplementowana inaczej niż każda inna odpowiedź podana tutaj. Popularną odpowiedź oznaczyłem jako poprawną.   -  person Andy McCluggage    schedule 08.08.2011
comment
Przepraszam, że to źle. Spojrzałem trochę głębiej i (od wersji 1.6.2) JQuery nadal wpisuje kontrole za pomocą porównań w formularzu.... toString.call(obj) === [tablica obiektu]   -  person Andy McCluggage    schedule 08.08.2011
comment
Dla obsługi IE8 zrobiłbym to if ('push' in variable.__proto__), najszybszy i być może najlepszy sposób sprawdzenia, czy jakaś var jest tablicą.   -  person thednp    schedule 06.07.2015
comment
jsben.ch/#/QgYAV — benchmark najpopularniejszych sposobów   -  person EscapeNetscape    schedule 24.10.2016
comment
stackoverflow.com/questions/4775722/check -jeśli-obiekt-jest-tablicą/   -  person shinobi    schedule 30.04.2017
comment
To pytanie zostało zadane wcześniej ... NIE, to pytanie zostało zadane PO tym   -  person Dexygen    schedule 12.11.2017
comment
No cóż, to jest StackOverflow   -  person Peppa    schedule 27.07.2020


Odpowiedzi (23)


Istnieje kilka sposobów sprawdzenia, czy zmienna jest tablicą, czy nie. Najlepszym rozwiązaniem jest to, które wybrałeś.

variable.constructor === Array

To najszybsza metoda w Chrome i najprawdopodobniej we wszystkich innych przeglądarkach. Wszystkie tablice są obiektami, więc sprawdzenie właściwości konstruktora jest szybkim procesem dla silników JavaScript.

Jeśli masz problemy z ustaleniem, czy właściwość obiektów jest tablicą, musisz najpierw sprawdzić, czy ta właściwość istnieje.

variable.prop && variable.prop.constructor === Array

Niektóre inne sposoby to:

Array.isArray(variable)

Aktualizacja 23 maja 2019 r. przy użyciu Chrome 75, krzycz do @AnduAndrici za to, że wróciłem do tego z jego pytaniem Ten ostatni jest moim zdaniem najbrzydszy i jest jednym z najwolniejszych najszybciej. Praca z około 1/5 szybkości, jak w pierwszym przykładzie. Ten facet jest około 2-5% wolniejszy, ale trudno to stwierdzić. Solidny w użyciu! Całkiem pod wrażeniem wyniku. Array.prototype, w rzeczywistości jest tablicą. możesz przeczytać więcej na ten temat tutaj https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray

variable instanceof Array

Ta metoda działa z około 1/3 szybkości jako pierwszy przykład. Nadal całkiem solidny, wygląda czyściej, jeśli chodzi o ładny kod, a nie o wydajność. Pamiętaj, że sprawdzanie numerów nie działa, ponieważ variable instanceof Number zawsze zwraca false. Aktualizacja: instanceof przyspiesza teraz o 2/3!

Więc kolejna aktualizacja

Object.prototype.toString.call(variable) === '[object Array]';

Ten facet jest najwolniejszy, gdy próbuje sprawdzić tablicę. Jest to jednak punkt kompleksowej obsługi dla każdego rodzaju, którego szukasz. Jednakże, ponieważ szukasz tablicy, po prostu użyj najszybszej metody opisanej powyżej.

Przeprowadziłem też test: http://jsperf.com/instanceof-array-vs-array-isarray/35 Więc baw się dobrze i sprawdź to.

Uwaga: @EscapeNetscape utworzył kolejny test, gdy jsperf.com nie działa. http://jsben.ch/#/QgYAV Chciałem się upewnić, że oryginalny link pozostanie zawsze, gdy jsperf wraca online.

person jemiloii    schedule 29.10.2014
comment
Aby rozszerzyć podaną odpowiedź, kolejny test jsperf tutaj przy użyciu funkcji testowania (. push && .pop), który jest najszybszy i obsługiwany we wszystkich przeglądarkach (nawet starych). Haczyk polega na tym, że być może obiekt ma właściwości „push” i „pop”, nie będąc tablicą. Zauważ także, że podczas testowania if jest tablicą z obiektem utworzonym (lub przekazanym) z innej ramki, większość testów zakończy się niepowodzeniem (ponieważ Tablica w danym oknie jest inna niż Tablica w oknie ościeżnicy). Istnieje również haczyk, jeśli tablica jest konstruowana za pomocą nowej Array lub dosłownie jako [..] - person Nikos M.; 15.12.2014
comment
Ciekawe, będę musiał zrobić jeszcze trochę testu przeglądarki. Chrome 38 na centos 7 ma push && pop o 10% szybciej niż konstruktor, jednak chrome 39 na Windows 8 ma konstruktora jako najszybszego bez ścisłego porównania, ponieważ konstruktor działa o 70% szybciej niż push && pop. Poczekam tylko na kolejny test, dzięki! - person jemiloii; 17.12.2014
comment
Zauważ, że jeśli nie masz pewności, czy zmienna jest zdefiniowana lub czy może mieć wartość NULL, najpierw wykonaj te sprawdzenia, ponieważ są to wspólne wartości/obiekty, które nie mają konstruktora. - person Michael Scott Cuthbert; 12.01.2015
comment
Skupiłem się tylko na części tablicy. Możesz łatwo mieć variable && variable.constructor === Array, aby upewnić się, że zmienna nie jest pusta lub niezdefiniowana. - person jemiloii; 12.01.2015
comment
Metody dodatkowe: !!~variable.constructor.toString().indexOf('Array()'), variable.constructor.toString() == Array().constructor.toString() (prawdopodobnie będą trochę wolniejsze) i Object.prototype.toString.call(variable) == '[object Array]' - person Ismael Miguel; 26.03.2015
comment
variable.constructor jest szybsze tylko do sprawdzania rzeczywistych tablic. Przy sprawdzaniu losowych obiektów (a tak będzie w świecie rzeczywistym, bo właśnie dlatego używasz tej funkcji) szybciej jest używać instanceof. jsperf.com/check-if-variable-is-array - person Dinu Sorin; 16.03.2016
comment
Używając Chrome 50.0.2657.0 na Centos 7, konstruktor jest dla mnie wciąż szybszy. Ponadto konstruktora można używać na wszystkim z wyjątkiem undefined i null. Możesz po prostu zrobić variable && variable.constructor. Należy również zauważyć, że 5 instanceof Number nie działa zgodnie z oczekiwaniami. Na przykład szuka prototypu, liczby nie mają prototypu, chyba że go ustawisz. Liczby mają konstruktory. - person jemiloii; 16.03.2016
comment
Inna dziwna uwaga: ` Object.prototype.toString.call(1) === '[Numer obiektu]';` to rzecz. JavaScript jest dziwaczny, więc Numbers ma prototypy. Tylko instanceof ich nie używa. Co jest dziwne, ponieważ według MDN jest to jedyny cel... - person jemiloii; 16.03.2016
comment
UWAGA: 'variable.constructor === Array' wyrzuci WYJĄTEK, jeśli zmienna ma wartość null, ale 'variable instanceof Array' nie! - person GorvGoyl; 05.10.2016
comment
jeśli spojrzysz, podałem przykład variable && variable.constructor === Array - person jemiloii; 05.10.2016
comment
Array.isArray(variable) nawet nie działał dla mnie. Pierwszy wypadł znakomicie! - person awe; 20.09.2017
comment
@awe w jakiej przeglądarce tego używasz? - person jemiloii; 20.09.2017
comment
Zgodnie z opublikowanym przez Ciebie JSPerf, Array.isArray jest najszybszy, a nie najwolniejszy - person Ferrybig; 25.09.2017
comment
z jakiej przeglądarki i wersji korzystasz? Dla mnie chrome/firefox, który szybko przetestowałem, konstruktor nadal jest najszybszy, jednak zauważalna jest poprawa w przypadku tablic zawierających tylko ciągi. Tablice zawierające tylko łańcuchy są bardzo szybkie. Przeprowadzę więcej testów. - person jemiloii; 25.09.2017
comment
Od wersji Chrome 59 isArray() wydaje się być znacznie szybsza, więc nie widzę powodu, aby nie używać isArray() we wszystkich sytuacjach. - person Hedley Smith; 10.10.2017
comment
Pierwotne pytanie nie wspominało o wydajności. Te mikrooptymalizacje będą nieistotne w prawie wszystkich przypadkach użycia - person Drenai; 15.02.2018
comment
Niektórzy lubią dostarczać dodatkowe informacje zamiast podstawowych minimów :) - person jemiloii; 18.02.2018
comment
Wszystkie twoje testy porównawcze są błędne – zarówno dlatego, że V8 (Chrome) zmienił kompilatory JIT, jak i dlatego, że Twoje testy nie są odpowiednie. Polecam zajrzeć na blog mraleph o wydajności i jsperf w szczególności. JSPerf jest jak układy scalone, które nie istnieją, a morfizm funkcji nie ma znaczenia dla kompilatora, podczas gdy w praktyce charakterystyka wydajności jest bardzo różna w zależności od tego, co silnik może udowodnić. - person Benjamin Gruenbaum; 06.07.2018
comment
Mianowicie, V8 może wstawić wartość true jeśli analiza typu wykaże, że wartość jest tablicą. Nie ma to jednak znaczenia, ponieważ instanceof jest zoptymalizowany do tej samej ścieżki. Co zabawne, porównanie .constructor jest wolniejsze. Cały punkt isArray to i tak cross-realms (tablice przekazywane między ramkami i kontekstami). - person Benjamin Gruenbaum; 06.07.2018
comment
czy variable.constructor === Array nadal jest akceptowaną odpowiedzią jako najszybsza/najskuteczniejsza? czy variable instanceof Array lub Array.isArray(variable) stały się bardziej opłacalne? -- pytanie, ponieważ odpowiedzi/komentarze są w niektórych miejscach dość stare. Bardzo doceniam :) - person Andu Andrici; 21.05.2019
comment
Wystarczy uruchomić testy, aby zobaczyć, zajmuje tylko chwilę. - person jemiloii; 23.05.2019
comment
@AnduAndrici Tak, pojawiła się dobra aktualizacja Array.isArray() w Chrome. Teraz druga najszybsza opcja. Solidny! - person jemiloii; 23.05.2019
comment
Chciałbym odpowiedzieć na drugie pytanie @AnduAndrici, ponieważ z odpowiedzi nie wynika już, które rozwiązanie jest najskuteczniejsze. - person Sebastian Gaweda; 17.07.2019
comment
to jasne @SebastianGaweda, przeczytaj odpowiedź. variable.constructor === Array Gdyby tak nie było, zaktualizowałbym go i podał powód aktualizacji. - person jemiloii; 31.07.2019
comment
@jemiloii Nie zgadzam się, żeby było jasne. Twoje aktualizacje mówią, że instanceof działa 2/3 szybkości oryginalnej odpowiedzi. Czy to znaczy szybciej? Wolniej? Sformułowanie jest nieco niejednoznaczne, choć trzeba przyznać, że kontekst akapitu wydaje się wskazywać wolniej. Przeprowadziłem kilka własnych testów, modyfikując kod w jsben.ch/QgYAV, ale te wyniki sugerowały, że instanceof był najszybszy . W związku z tym jsben.ch/QgYAV zawiera teraz link do pustego testu porównawczego. - person Sebastian Gaweda; 31.07.2019
comment
Świetna odpowiedź. Dziękuję Ci. - person Anjana Silva; 11.12.2019
comment
tak wiele zmian sprawia, że ​​Twoja odpowiedź jest nieczytelna. Dlatego przeceniam... - person Clint Eastwood; 27.01.2020
comment
Całkiem dobrze, lubię oglądać aktualizacje javascript na przestrzeni lat. - person jemiloii; 28.01.2020
comment
Jeśli zamierzasz edytować swoją odpowiedź, rozważ uczynienie jej bardziej czytelną dla tych, którzy jej wcześniej nie czytali. - person AtilioA; 11.06.2020

Możesz również użyć:

if (value instanceof Array) {
  alert('value is Array!');
} else {
  alert('Not an array');
}

Wydaje mi się to całkiem eleganckie rozwiązanie, ale dla każdego własne.

Edytować:

Od ES5 jest teraz również:

Array.isArray(value);

Ale to się zepsuje w starszych przeglądarkach, chyba że używasz wypełniaczy (w zasadzie... IE8 lub podobnych).

person Brett Bender    schedule 20.04.2009
comment
Sugeruję, aby trzymać się tego operatora instanceof, jeśli nie pracujesz z wieloma ramkami. To jest właściwy sposób sprawdzenia typu obiektu. - person BYK; 20.04.2009
comment
Jedynym przypadkiem, w którym to się nie powiedzie, jest próba przetestowania tablicy lub obiektu od Array instanceof Object == true. - person Pierre; 29.11.2012
comment
Jeśli używasz jQuery do przekazywania elementów z find('code') lub czymś podobnym, chciałbyś sprawdzić zmienną za pomocą variable instanceof Object, ponieważ nie jest to instancja tablicy. - person tuck; 01.05.2013
comment
Aby wzmocnić punkt @BYK, działa to tylko z obiektami w tej samej ramce. Nie polegaj na tym, jeśli pracujesz z wieloma ramkami! - person Cory Klein; 25.09.2013
comment
Nie działa w niektórych przypadkach: Array.prototype instanceof Array; // false (powinno być prawdziwe); także ({ __proto__ : Array.prototype }) instanceof Array; // true (powinno być fałszywe) - person vortexwolf; 04.11.2013
comment
Nie znam się na wnętrzach JS - czy typ prototypu ma być taki sam jak typ obiektu? - person Brett Bender; 04.11.2013
comment
@BrettBender Jeśli nadal jesteś aktywny, czy możesz zaktualizować swoją odpowiedź, aby odzwierciedlić to, że od ES5 mamy Array.isArray? - person Nobbynob Littlun; 22.05.2014
comment
@AndrewK zobacz odpowiedź Feli Winkelmolen, która wykorzystuje metodę Array.isArray. Jeśli chodzi o tę odpowiedź, prawdopodobnie nie jest dobrym pomysłem przekształcanie odpowiedzi w inną odpowiedź poprzez edycję. - person muffin; 25.08.2014
comment
Lub jeśli nie interesują Cię stare przeglądarki, możesz użyć Array.isArray(arr) - person Dominic; 13.10.2014
comment
To jest miłe, ale użyj zmiennej.constructor === Array, zdecydowanie najszybszej metody w javascript. jsperf.com/instanceof-array-vs-array-isarray - person jemiloii; 29.10.2014
comment
@muffin: dlaczego dobrym pomysłem jest pozostawienie odpowiedzi nieaktualnej o pięć lat? Jak wiesz, wielu użytkowników nie przeczyta komentarzy pod odpowiedzią (tak bardzo, jak byśmy tego chcieli), nie mówiąc już o tym, że niektóre z tych komentarzy są ukryte w obszarze Pokaż więcej. - person Dan Dascalescu; 04.12.2014
comment
@DanDascalescu Masz rację, że ukrywanie cennych informacji nie jest dobre. Ale myślę, że niewłaściwe jest zmienianie czyjejś odpowiedzi do punktu, w którym nie pozostaje ona już w istocie tą samą odpowiedzią. Być może dodanie zawiadomienia/linia FYI edytowanej do najwyżej głosowanej odpowiedzi byłoby pomocne w sposób, który nie zdradza integralności oryginalnej odpowiedzi, ale jeśli jest to wskazany środek zaradczy, system powinien uwzględnić go na tym samym poziomie, co głosowanie nad i przyjmowanie odpowiedzi. W każdym razie nie przeglądam już meta: nie pamiętam, jakie (moje poczucie) konsensus dotyczy integralności odpowiedzi. - person muffin; 04.12.2014
comment
Jest to poprawne, ponieważ poradzi sobie również z niezdefiniowaną lub zerową wartością. - person James Nurse; 12.08.2015

Istnieje wiele rozwiązań z własnymi dziwactwami. Ta strona zawiera dobry przegląd . Jednym z możliwych rozwiązań jest:

function isArray(o) {
  return Object.prototype.toString.call(o) === '[object Array]'; 
}
person Peter Smit    schedule 20.04.2009
comment
Jeśli czytasz uważnie, mówi się, że ta metoda jest potrzebna podczas pracy z dokumentami wieloklatkowymi, co nie jest zalecane. Ta metoda może łatwo pominąć niewielką zmianę w funkcji toString. - person BYK; 20.04.2009
comment
W związku z tym podany jest link, aby Brett mógł je sprawdzić i zobaczyć, w jakim przypadku jego funkcja musi działać - person Peter Smit; 20.04.2009
comment
Zobacz moją odpowiedź poniżej. Polecam sposób Petera Smita. - person Brian; 29.06.2012
comment
Ta metoda jest zalecana przez Mozillę . - person Hank; 28.05.2015

Zauważyłem, że ktoś wspomniał o jQuery, ale nie wiedziałem, że istnieje funkcja isArray(). Okazuje się, że został dodany w wersji 1.3.

jQuery implementuje to tak, jak sugeruje Peter:

isArray: function( obj ) {
    return toString.call(obj) === "[object Array]";
},

Mając już dużo wiary w jQuery (zwłaszcza w ich techniki kompatybilności z różnymi przeglądarkami), albo zaktualizuję do wersji 1.3 i użyję ich funkcji (pod warunkiem, że aktualizacja nie spowoduje zbyt wielu problemów) lub użyję tej sugerowanej metody bezpośrednio w moim kod.

Wielkie dzięki za sugestie.

person Andy McCluggage    schedule 20.04.2009
comment
Zobacz ten artykuł, aby uzyskać dobra dyskusja na ten temat. Konkluzja jest taka, aby skorzystać z tego rozwiązania. - person Nick G.; 12.03.2014
comment
To daje mi błąd SCRIPT65535 w IE10. - person polm23; 27.05.2014

W nowoczesnych przeglądarkach (i niektórych starszych przeglądarkach) możesz to zrobić

Array.isArray(obj)

(Obsługiwane przez Chrome 5, Firefox 4.0, IE 9, Opera 10.5 i Safari 5)

Jeśli chcesz obsługiwać starsze wersje IE, możesz użyć es5-shim do wypełnienia tablicy .isArray; lub dodaj następujące

# only implement if no native implementation is available
if (typeof Array.isArray === 'undefined') {
  Array.isArray = function(obj) {
    return Object.prototype.toString.call(obj) === '[object Array]';
  }
};

Jeśli używasz jQuery, możesz użyć jQuery.isArray(obj) lub $.isArray(obj). Jeśli używasz podkreślenia, możesz użyć _.isArray(obj)

Jeśli nie musisz wykrywać tablic utworzonych w różnych ramkach, możesz po prostu użyć instanceof

obj instanceof Array

Uwaga: słowo kluczowe arguments, którego można użyć do uzyskania dostępu do argumentu funkcji, nie jest tablicą, mimo że (zazwyczaj) zachowuje się tak:

var func = function() {
  console.log(arguments)        // [1, 2, 3]
  console.log(arguments.length) // 3
  console.log(Array.isArray(arguments)) // false !!!
  console.log(arguments.slice)  // undefined (Array.prototype methods not available)
  console.log([3,4,5].slice)    // function slice() { [native code] } 
}
func(1, 2, 3)

person Fela    schedule 08.01.2014
comment
To chyba najlepsze najnowocześniejsze podejście. Widziałem go wraz z wypełnieniem na MDN, co oznacza, że ​​Mozilla mu ufa developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ - person John; 12.04.2014
comment
Nie brakuje ci prototype tam? Wygląda na to, że powinno być Object.prototype.toString.call. - person Brock; 20.11.2014

To stare pytanie, ale mając ten sam problem, znalazłem bardzo eleganckie rozwiązanie, którym chcę się podzielić.

Dodanie prototypu do Array sprawia, że ​​jest to bardzo proste

Array.prototype.isArray = true;

Teraz raz, jeśli masz obiekt, który chcesz przetestować, aby sprawdzić, czy jest to tablica, wystarczy sprawdzić nową właściwość

var box = doSomething();

if (box.isArray) {
    // do something
}

isArray jest dostępna tylko wtedy, gdy jest to tablica

person Ibu    schedule 24.10.2011
comment
to brzmi dla mnie tak fajnie! to może być natywne. btw działa nawet wtedy, gdy tablica została utworzona przed prototypowaniem? - person Vitim.us; 12.11.2011
comment
@Vitimtk Prototyp działa jako rezerwa dla rzeczywistego obiektu, więc powinno to działać, nawet jeśli dana tablica już istniała. Oczywiście nie zadziała, dopóki linia źródłowa nie zostanie przetworzona. - person Markus Bruckner; 28.12.2011
comment
Zakładając, że nikt tego nie zrobi Object.prototype.isArray = true;! :( - person ErikE; 30.09.2012
comment
Zauważ, że w ES5 Array.isArray jest metodą (np. Array.isArray([1,2,3]) === true), więc @ErikE nie był trollem. Unikałbym podążania za tą odpowiedzią, ponieważ zepsuje ona kod w niektórych nowoczesnych przeglądarkach. - person JaredMcAteer; 11.07.2013
comment
@JaredMcAteer Twój przykład jest poprawny. Jednak ErikE nie jest powiązany, Array != [1,2,3] . Więc nadal możesz zrobić [1,2,3].isArray === true z moim rozwiązaniem - person Ibu; 11.07.2013
comment
@Ibu i możesz zrobić {}.isArray === true z moim rozwiązaniem, o co chodziło... - person ErikE; 12.07.2013
comment
Modyfikowanie prototypu typów danych to według mnie zła praktyka - person BentOnCoding; 24.09.2014
comment
@BentOnCoding co z Array.prototype["com.my.unique.name"].isArray ;) - person SOFe; 28.12.2018

Przez Crockford:

function typeOf(value) {
    var s = typeof value;
    if (s === 'object') {
        if (value) {
            if (value instanceof Array) {
                s = 'array';
            }
        } else {
            s = 'null';
        }
    }
    return s;
}

Główną wadą, o której wspomina Crockford, jest niemożność prawidłowego określenia tablic, które zostały utworzone w innym kontekście, np. window. Ta strona ma znacznie bardziej zaawansowaną wersję, jeśli to nie wystarcza.

person Hank Gay    schedule 20.04.2009

Jeśli masz do czynienia tylko z EcmaScript 5 i nowszymi, możesz użyć wbudowanej funkcji Array.isArray

e.g.,

Array.isArray([])    // true
Array.isArray("foo") // false
Array.isArray({})    // false
person JaredMcAteer    schedule 11.07.2013

Osobiście podoba mi się sugestia Petera: https://stackoverflow.com/a/767499/414784 (dla ECMAScript 3. Dla ECMAScript 5, użyj Array.isArray())

Komentarze pod postem wskazują jednak, że jeśli w ogóle zmieni się toString(), to ten sposób sprawdzenia tablicy się nie powiedzie. Jeśli naprawdę chcesz być konkretny i upewnić się, że toString() nie zostało zmienione i nie ma problemów z atrybutem klasy obiektów ([object Array] to atrybut klasy obiektu będącego tablicą), to polecam zrobić coś takiego:

//see if toString returns proper class attributes of objects that are arrays
//returns -1 if it fails test
//returns true if it passes test and it's an array
//returns false if it passes test and it's not an array
function is_array(o)
{
    // make sure an array has a class attribute of [object Array]
    var check_class = Object.prototype.toString.call([]);
    if(check_class === '[object Array]')
    {
        // test passed, now check
        return Object.prototype.toString.call(o) === '[object Array]';
    }
    else
    {
        // may want to change return value to something more desirable
        return -1; 
    }
}

Zauważ, że w JavaScript The Definitive Guide 6th edition, 7.10, jest napisane, że Array.isArray() jest zaimplementowany przy użyciu Object.prototype.toString.call() w ECMAScript 5. Zauważ też, że jeśli masz zamiar martwić się o zmianę implementacji toString(), powinieneś również martwić się o zmianę wszystkich innych wbudowanych metod . Dlaczego warto korzystać z push()? Ktoś może to zmienić! Takie podejście jest głupie. Powyższy czek jest proponowanym rozwiązaniem dla tych, którzy martwią się toString() zmianą, ale uważam, że czek jest niepotrzebny.

person Brian    schedule 03.12.2011
comment
Dobre połączenie ze standardem ECMAScript 5. Oczywiście nie możesz zagwarantować, że przeglądarka to obsługuje, ale powinien to być pierwszy sposób na zaewidencjonowanie nowego kodu. - person styfle; 14.12.2012
comment
Zacznę od stwierdzenia, że ​​to trochę przesadzone. Czy jednak taki test byłby bardziej niezawodny?: return Object.prototype.toString.call(o) === Object.prototype.toString.call([]); - person Grant Lindsay; 24.06.2014

Kiedy wysłałem to pytanie, wersja JQuery, której używałem, nie zawierała funkcji isArray. Gdyby tak było, prawdopodobnie użyłbym go po prostu ufając, że ta implementacja jest najlepszym niezależnym od przeglądarki sposobem przeprowadzenia tego konkretnego sprawdzenia typu.

Ponieważ JQuery teraz oferuje tę funkcję, zawsze bym jej używał...

$.isArray(obj);

(od wersji 1.6.2) Nadal jest zaimplementowany przy użyciu porównań na ciągach w formularzu

toString.call(obj) === "[object Array]"
person Andy McCluggage    schedule 08.08.2011

Pomyślałem, że dodałbym kolejną opcję dla tych, którzy mogą już używać biblioteki Underscore.js w swoim skrypcie. Underscore.js ma funkcję isArray() (patrz http://underscorejs.org/#isArray).

_.isArray(object) 

Zwraca true, jeśli obiekt jest Array.

person Benjen    schedule 16.03.2012
comment

Złożyłem JSFiddle, aby utworzyć poziomą oś czasu za pomocą CSS i JQuery. Zachowanie osi czasu jest następujące:

Kiedy strona się ładuje, „timelineSlider” zawsze ustawia się pod „Link 1”. Klikając każdy element listy o nazwie „Link”, „timelineSlider” przesuwa się w kierunku i pod tym elementem listy.

Obecnie działa sekwencyjnie, gdy użytkownik kliknie Link1, Link2, Link3, a następnie Link4. Ale chciałbym, aby użytkownik klikał dowolny element listy w dowolnej kolejności, a „timelineSlider” powinien przesuwać się w prawo lub w lewo lub nie zmieniać pozycji, w zależności od poprzedniej pozycji „timelineSlider”. Jak mogę zmienić mój kod JS, aby to zrobić?

JSFiddle

$(document).ready(function() {
  $("li").click(function() {
    //Get Initial timelineSlider Margin
    var timelineSliderMargin = parseInt($('.timelineSlider').css('margin-left'));
    //Slide the box to the link clicked (left or right) depending on box position
    $(".timelineSlider").animate({
      'margin-left': (parseInt(calculate(0)) + parseInt($('.timelineSlider').css('margin-left'))) + 'px'
    });
  });
});

function calculate(i) {
  var sum = 0;
  for (var j = 0; j <= i; j++) {
    sum = sum + $("ul li:eq(" + j + ")").outerWidth(true);
  }
  return sum;
}
div.eventsWrapper {
  height: 75px;
  margin-left: 5px;
  position: absolute;
  width: 800px;
}
.eventsConnector {
  background: #0070c0 none repeat scroll 50% 50%;
  height: 3px;
  left: 0;
  margin-left: 185px;
  margin-top: -31px;
  position: absolute;
  transition: transform 0.4s ease 0s;
  width: 512px;
  z-index: -1;
}
#events {
  z-index: 2;
}
#events ul {
  list-style-type: none;
  padding: 0;
  margin: 0;
}
#events li {
  display: inline-block;
}
#events a {
  display: block;
  width: 50px;
  height: 50px;
  border-radius: 50%;
  border: 5px #0070c0 solid;
  text-transform: uppercase;
  text-decoration: none;
  font-size: 15px;
  text-align: center;
  line-height: 50px;
  margin-left: 125px;
  z-index: 3;
  color: #666666;
  background-color: #0070c0;
}
#events a .event {
  background-color: #ffffff;
  border: 1px solid #ffffff;
  border-radius: 50%;
  color: #666666;
  display: block;
  font-size: 15px;
  height: 48px;
  margin-left: 0;
  margin-top: 0;
  position: relative;
  text-align: center;
  text-decoration: none;
  text-transform: uppercase;
  width: 48px;
  z-index: 4;
}
.timelineSlider {
  width: 110px;
  height: 66px;
  border: 0px;
  margin-left: 95px;
  margin-top: 10px;
  position: absolute;
  z-index: 2;
  background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
<div class="eventsWrapper">
  <div id="events">
    <ul>
      <li>
        <a href="/pl#1">
          <div class="event">LINK1</div>
        </a>
      </li>
      <li>
        <a href="/pl#2">
          <div class="event">LINK2</div>
        </a>
      </li>
      <li>
        <a href="/pl#3">
          <div class="event">LINK3</div>
        </a>
      </li>
      <li>
        <a href="/pl#4">
          <div class="event">LINK4</div>
        </a>
      </li>
    </ul>
  </div>
  <div class="eventsConnector"></div>
  <div class="timelineSlider">Slide this box to the link clicked.</div>
</div>

- person Kris; 24.04.2014
comment
Ta sama funkcja jest obecna w Lodash - person Jundiaius; 13.04.2016

Jeśli używasz Angulara, możesz użyć funkcji angular.isArray()

var myArray = [];
angular.isArray(myArray); // returns true

var myObj = {};
angular.isArray(myObj); //returns false

http://docs.angularjs.org/api/ng/function/angular.isArray

person joseph.l.hunsaker    schedule 19.03.2014
comment
Możesz także używać innych niż Angular, ale tylko IE9+ i wszystkich standardowych przeglądarek: ‹pre›‹code› Array.isArray(myArray); //zwraca wartość true Array.isArray(myObj); //zwraca fałsz ‹/kod› ‹/pre› - person PDA; 17.07.2014

W JavaScript The Good Parts Crockforda znajduje się funkcja sprawdzająca, czy podany argument jest tablicą:

var is_array = function (value) {
    return value &&
        typeof value === 'object' &&
        typeof value.length === 'number' &&
        typeof value.splice === 'function' &&
        !(value.propertyIsEnumerable('length'));
};

On tłumaczy:

Najpierw pytamy, czy wartość jest prawdziwa. Robimy to, aby odrzucić wartości null i inne fałszywe wartości. Po drugie, pytamy, czy typem wartości jest „obiekt”. Dotyczy to obiektów, tablic i (co dziwne) null. Po trzecie, pytamy, czy wartość ma właściwość length, która jest liczbą. To będzie zawsze prawdziwe dla tablic, ale zwykle nie dla obiektów. Po czwarte, pytamy, czy wartość zawiera metodę łączenia. To znowu będzie prawdziwe dla wszystkich tablic. Na koniec pytamy, czy właściwość length jest przeliczalna (czy długość zostanie wytworzona przez pętlę for in?). To będzie fałszywe dla wszystkich tablic. Jest to najbardziej wiarygodny test na tablicę, jaki znalazłem. Szkoda, że ​​jest to tak skomplikowane.

person Yunzhou    schedule 03.12.2013
comment
I to były tylko dobre części. Wyobraź sobie, że JavaScript The Bad Parts zostanie opublikowany... - person FrancescoMM; 30.01.2017

Uniwersalne rozwiązanie znajduje się poniżej:

Object.prototype.toString.call(obj)=='[object Array]'

Począwszy od ECMAScript 5, formalnym rozwiązaniem jest:

Array.isArray(arr)

Również dla starych bibliotek JavaScript możesz znaleźć poniższe rozwiązanie, chociaż nie jest ono wystarczająco dokładne:

var is_array = function (value) {
    return value &&
    typeof value === 'object' &&
    typeof value.length === 'number' &&
    typeof value.splice === 'function' &&
    !(value.propertyIsEnumerable('length'));
};

Rozwiązania pochodzą z http://www.pixelstech.net/topic/85-How-to-check-whether-an-object-is-an-array-or-not-in-JavaScript

person PixelsTech    schedule 11.01.2015

kod odesłany z https://github.com/miksago/Evan.js/blob/master/src/evan.js

  var isArray = Array.isArray || function(obj) {
    return !!(obj && obj.concat && obj.unshift && !obj.callee);};
person didxga    schedule 26.05.2011
comment
Dlaczego testujesz zarówno concat, jak i unshift, nie wystarczy, aby przetestować dla unshift? - person Marco Demaio; 18.02.2014
comment
Im więcej metod sprawdzimy, czy Array ma ruch, prawdopodobnie jest to tablica. Inne obiekty mogą mieć concat lub unshift, ale z mniejszym prawdopodobieństwem oba. - person Kris; 24.04.2014

Używałem tego wiersza kodu:

if (variable.push) {
   // variable is array, since AMAIK only arrays have push() method.
}
person Saeed Neamati    schedule 06.01.2013
comment
To wcale nie jest dobre rozwiązanie. Dzięki temu rozwiązaniu każdy obiekt z właściwością push, która jest prawdziwa, będzie uważany za tablicę. - person teleclimber; 28.04.2014

Dla tych, którzy kodują golfa, niewiarygodny test z najmniejszą liczbą znaków:

function isArray(a) {
  return a.map;
}

Jest to powszechnie używane podczas przechodzenia/spłaszczania hierarchii:

function golf(a) {
  return a.map?[].concat.apply([],a.map(golf)):a;
}

input: [1,2,[3,4,[5],6],[7,[8,[9]]]]
output: [1, 2, 3, 4, 5, 6, 7, 8, 9]
person Joe Frambach    schedule 24.10.2013

Z w3schools:

function isArray(myArray) {
    return myArray.constructor.toString().indexOf("Array") > -1;
}
person Jahid    schedule 29.03.2015

Podobała mi się odpowiedź Briana:

function is_array(o){
    // make sure an array has a class attribute of [object Array]
    var check_class = Object.prototype.toString.call([]);
    if(check_class === '[object Array]')    {
        // test passed, now check
        return Object.prototype.toString.call(o) === '[object Array]';
    } else{
        // may want to change return value to something more desirable
        return -1; 
    }
}

ale możesz po prostu zrobić tak:

return Object.prototype.toString.call(o) === Object.prototype.toString.call([]);
person zeageorge    schedule 20.04.2013

Stworzyłem ten mały fragment kodu, który może zwracać prawdziwe typy.

Nie jestem jeszcze pewien wydajności, ale to próba właściwego rozpoznania typu.

https://github.com/valtido/better-typeOf również trochę o tym napisał http://www.jqui.net/jquery/better-typeof-than-the-javascript-native-typeof/

działa podobnie do obecnego typeof.

var user = [1,2,3]
typeOf(user); //[object Array]

Uważa, że ​​może wymagać trochę dopracowania, a biorąc pod uwagę rzeczy, nie natknąłem się na to ani nie przetestowałem poprawnie. więc mile widziane są dalsze ulepszenia, niezależnie od tego, czy są one związane z wydajnością, czy niepoprawnym raportowaniem typu typeOf.

person Val    schedule 28.07.2014

Myślę, że najlepszym sposobem jest użycie myObj.constructor==Object i myArray.constructor==Array. Jest prawie 20x szybszy niż przy użyciu metody toString(). Jeśli rozszerzasz obiekty swoimi własnymi konstruktorami i chcesz, aby te kreacje również były uważane za "obiekty", to nie działa, ale poza tym jest znacznie szybsze. typeof jest tak samo szybki jak metoda konstruktora, ale typeof []== 'object' zwraca wartość true, co często jest niepożądane. http://jsperf.com/constructor-vs-tostring

należy zauważyć, że null.constructor zgłosi błąd, więc jeśli możesz sprawdzać wartości null, musisz najpierw zrobić if(testThing!==null){}

person user1585789    schedule 24.08.2014

Ponieważ właściwość .length jest specjalna dla tablic w javascript, możesz po prostu powiedzieć

obj.length === +obj.length // true if obj is an array

Underscorejs i kilka innych bibliotek używa tej krótkiej i prostej sztuczki.

person TypingTurtle    schedule 02.03.2014
comment
Czy mógłbyś wyjaśnić, jak to działa? Głównie, co robi „+”? - person Andy McCluggage; 03.03.2014
comment
To dobrze, ale jest również prawdziwe, gdy obiekt jest funkcją lub ciągiem znaków, a także dowolnym innym obiektem o długości właściwości typu number. Czemu? Cóż, operator jednoargumentowy + faktycznie rzutuje zmienną jako liczbę. Więc w zasadzie sprawdzają, czy obj.length jest liczbą. [Object Object] nie ma długości właściwości, jest niezdefiniowany, więc gdy rzutujesz undefined jako liczbę, staje się ona NaN, powyższe sprawdzenie jest fałszywe. Zwraca więc true, jeśli długość właściwości obiektu jest liczbą, co w przypadku tablic, łańcuchów i funkcji byłoby prawdą. Podkreślenie musi robić coś więcej niż tylko to. - person John; 12.04.2014

Coś, co właśnie wymyśliłem:

if (item.length) //This is an array else //not an array

person trololol    schedule 12.02.2015
comment
var element = 'ta_to_nie_tablica'; - person kev; 06.03.2015
comment
To złe rozwiązanie! Sznurek ma również długość. - person pmrotule; 09.03.2015
comment
Właściwie ciąg to tablica znaków, więc w istocie to działa - person Shingala94; 13.03.2015
comment
@PatrickNijhuis - string jest typem pierwotnym w javascript, podczas gdy tablica jest obiekt. W języku potocznym masz rację — ciąg znaków to tablica znaków — ale w javascript to twierdzenie jest błędne. To ważne rozróżnienie i powód, dla którego jest to zła odpowiedź. - person wahwahwah; 27.03.2015
comment
Nie, tablica o zerowej długości nadal jest tablicą. - person Dave Burton; 14.08.2016
comment
możesz wpisać typeof item == 'object', a odpowiedź może być akceptowalna - person Abz Rockers; 31.08.2017
comment
co ważniejsze: pusta tablica nie przejdzie tego testu, ponieważ 0 jest fałszywe - person David Schumann; 26.03.2020