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ć?
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ć?
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.
variable && variable.constructor === Array
, aby upewnić się, że zmienna nie jest pusta lub niezdefiniowana.
- person jemiloii; 12.01.2015
!!~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
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
instanceof
ich nie używa. Co jest dziwne, ponieważ według MDN jest to jedyny cel...
- person jemiloii; 16.03.2016
variable && variable.constructor === Array
- person jemiloii; 05.10.2016
Array.isArray(variable)
nawet nie działał dla mnie. Pierwszy wypadł znakomicie!
- person awe; 20.09.2017
Array.isArray
jest najszybszy, a nie najwolniejszy
- person Ferrybig; 25.09.2017
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
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
variable.constructor === Array
Gdyby tak nie było, zaktualizowałbym go i podał powód aktualizacji.
- person jemiloii; 31.07.2019
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
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).
Array instanceof Object == true
.
- person Pierre; 29.11.2012
variable instanceof Object
, ponieważ nie jest to instancja tablicy.
- person tuck; 01.05.2013
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
Array.isArray(arr)
- person Dominic; 13.10.2014
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]';
}
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.
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)
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
Object.prototype.isArray = true;
! :(
- person ErikE; 30.09.2012
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
{}.isArray === true
z moim rozwiązaniem, o co chodziło...
- person ErikE; 12.07.2013
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.
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
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.
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]"
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.
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ć?
$(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>
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
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.
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
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);};
concat
, jak i unshift
, nie wystarczy, aby przetestować dla unshift
?
- person Marco Demaio; 18.02.2014
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.
}
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]
Z w3schools:
function isArray(myArray) {
return myArray.constructor.toString().indexOf("Array") > -1;
}
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([]);
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.
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){}
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.
Coś, co właśnie wymyśliłem:
if (item.length)
//This is an array
else
//not an array
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