Jaki jest najszybszy sposób na policzenie liczby kluczy / właściwości obiektu? Czy można to zrobić bez iteracji nad obiektem? tzn. bez robienia
var count = 0;
for (k in myobj) if (myobj.hasOwnProperty(k)) count++;
(Firefox zapewnił magiczną __count__
właściwość, ale została ona usunięta gdzieś w pobliżu wersji 4.)
Odpowiedzi:
Aby to zrobić w dowolnym środowisku zgodnym z ES5 , takim jak Node , Chrome, IE 9+, Firefox 4+ lub Safari 5+:
źródło
Możesz użyć tego kodu:
Następnie możesz użyć tego również w starszych przeglądarkach:
źródło
(Object.prototype.hasOwnProperty.call(obj, k))
?hasOwnProperty
konieczne jest sprawdzenie . Zwraca tylko właściwości ustawione na samym obiekcie.obj.hasOwnProperty(k)
(faktycznie zrobiłem to w moim oryginalnym poście, ale zaktualizowałem go później).hasOwnProperty
jest dostępny na każdym obiekcie, ponieważ jest on częściąObject
prototypu, ale w rzadkich przypadkach, gdy ta metoda zostanie usunięta lub zastąpiona, możesz otrzymać nieoczekiwane wyniki. Wywołanie go zObject.prototype
niego czyni go trochę bardziej niezawodnym. Powodem użyciacall
jest to, że chcesz wywołać metodęobj
zamiast na prototypie.Jeśli używasz Underscore.js , możesz użyć _.size (dzięki @douwe):
_.size(obj)
Alternatywnie możesz również użyć klawiszy _., Które mogą być bardziej zrozumiałe dla niektórych:
_.keys(obj).length
Bardzo polecam Underscore, to ciasna biblioteka do robienia wielu podstawowych rzeczy. Tam, gdzie to możliwe, dopasowują ECMA5 i przechodzą na implementację natywną.
W przeciwnym razie popieram odpowiedź @ Avi. Zredagowałem go, aby dodać link do dokumentu MDC, który zawiera metodę keys (), którą możesz dodać do przeglądarek innych niż ECMA5.
źródło
_.keys(obj).length
działało najlepiej dla mnie, ponieważ mój obiekt zwracany jest czasem zwykłym ciągiem bez właściwości._.size(obj)
zwraca mi długość łańcucha, a_.keys(obj).length
zwraca 0.Object.keys
wewnętrznie. Znak podkreślenia kopiuje również każdy klucz do tablicy wewnątrzfor..in
pętli, jeśliObject.keys
nie jest zdefiniowany.Standardowa implementacja obiektu ( ES5.1 Object Internal Properties and Methods ) nie wymaga
Object
śledzenia liczby kluczy / właściwości, dlatego nie powinno być standardowego sposobu określania wielkościObject
bez jawnego lub niejawnego iterowania kluczy.Oto najczęściej stosowane alternatywy:
1. Object.keys () w ECMAScript
Object.keys(obj).length;
Działa poprzez wewnętrzne iterowanie po klawiszach w celu obliczenia tablicy tymczasowej i zwraca jej długość.2. Rozwiązania oparte na bibliotece
Wiele przykładów opartych na bibliotece gdzie indziej w tym temacie to przydatne idiomy w kontekście ich biblioteki. Jednak z punktu widzenia wydajności nie ma nic do zyskania w porównaniu z doskonałym kodem bez biblioteki, ponieważ wszystkie te metody biblioteczne faktycznie otaczają pętlę for lub ES5
Object.keys
(natywną lub shimmed ).3. Optymalizacja pętli for
Najwolniej część takiej dla pętli jest na ogół
.hasOwnProperty()
wywołania z powodu obciążania wywołaniu funkcji. Kiedy więc chcę tylko liczby wpisów obiektu JSON, po prostu pomijam.hasOwnProperty()
wywołanie, jeśli wiem, że żaden kod nie był ani nie będzie rozszerzanyObject.prototype
.W przeciwnym razie twój kod może być bardzo nieznacznie zoptymalizowany poprzez utworzenie
k
local (var k
) i użycie operatora increment-increment (++count
) zamiast postfix.Kolejny pomysł polega na buforowaniu
hasOwnProperty
metody:To, czy jest to szybsze, czy nie w danym środowisku, jest kwestią testu porównawczego. W każdym razie można oczekiwać bardzo ograniczonego wzrostu wydajności.
źródło
var k in myobj
zwiększać wydajność? O ile mi wiadomo, tylko funkcje deklarują nowy zakres w JavaScript. Czy pętle wewnętrzne są wyjątkiem od tej reguły?for (var k in myobj) hasOwn.call(myobj, k) && ++count;
tj. zastąpienie instrukcji if prostym znakiem &&?Object.getOwnPropertyNames(obj).length
:; o wiele prostsze.Jeśli faktycznie masz problem z wydajnością, sugerowałbym zawinięcie wywołań dodających / usuwających właściwości do / z obiektu funkcją, która również zwiększa / zmniejsza odpowiednio nazwaną właściwość (rozmiar?).
Wystarczy tylko raz obliczyć początkową liczbę nieruchomości i przejść od tego miejsca. Jeśli nie ma rzeczywistego problemu z wydajnością, nie przejmuj się. Po prostu zawiń ten fragment kodu w funkcji
getNumberOfProperties(object)
i gotowe.źródło
Jak stwierdził Avi Flax https://stackoverflow.com/a/4889658/1047014
zrobi lewę dla wszystkich wyliczalnych właściwości w twoim obiekcie, ale także włączy właściwości niewymierne, których możesz zamiast tego użyć
Object.getOwnPropertyNames
. Oto różnica:Jak stwierdzono tutaj, ma to takie samo wsparcie przeglądarki jak
Object.keys
Jednak w większości przypadków możesz nie chcieć uwzględniać niezliczonych elementów w tego typu operacjach, ale zawsze dobrze jest znać różnicę;)
źródło
Object.getOwnPropertyNames
, byłeś tu jedynym ...Nie znam żadnego sposobu, aby to zrobić, jednak aby zminimalizować liczbę iteracji, możesz spróbować sprawdzić istnienie,
__count__
a jeśli nie istnieje (tzn. Nie Firefox), możesz iterować obiekt i zdefiniować do późniejszego wykorzystania np .:W ten sposób skorzysta z niego dowolna obsługa przeglądarki
__count__
, a iteracje będą przeprowadzane tylko dla tych, które tego nie robią. Jeśli liczba się zmienia i nie możesz tego zrobić, zawsze możesz ustawić funkcję:W ten sposób za każdym razem, gdy odwołujesz się do myobj.
__count__
funkcja uruchomi się i przeliczy.źródło
Object.prototype.__count__
jest usuwany w Gecko 1.9.3: whereswalden.com/2010/04/06/… count -property-of-objects-is-being-Object.__count__
zniknął, a także dobra gra.Aby wykonać iterację na Avi Flax, odpowiedz Object.keys (obj) .length jest poprawny dla obiektu, który nie ma powiązanych z nim funkcji
przykład:
przeciw
kroki, aby tego uniknąć:
nie umieszczaj funkcji w obiekcie, w którym chcesz policzyć liczbę kluczy
użyj osobnego obiektu lub stwórz nowy obiekt specjalnie dla funkcji (jeśli chcesz policzyć, ile funkcji jest w pliku za pomocą
Object.keys(obj).length
)również tak, w moim przykładzie użyłem modułu _ lub podkreślenia z nodejs
dokumentację można znaleźć tutaj http://underscorejs.org/, a także jej źródło na github i różne inne informacje
I wreszcie implementacja lodash https://lodash.com/docs#size
_.size(obj)
źródło
Array(obj).length
: To nie działa. http://jsfiddle.net/Jhy8M/false
, chociaż nie znalazłem jeszcze żadnej dokumentacji na temat tego, covar obj = { a: true, b: true }
może się różnićvar obj = {}; obj.a = true; obj.b = true;
lub po prostu, jeśli inna interpretacja / semantyka W3 ma zostały adoptowane przez Chrome.jak odpowiedziano powyżej:
Object.keys(obj).length
Ale: ponieważ mamy teraz prawdziwą klasę Map w ES6, sugerowałbym użycie jej zamiast używania właściwości obiektu.
źródło
Dla tych, którzy mają Underscore.js w swoim projekcie, możesz:
lub funkcjonalny styl:
źródło
Oto kilka testów wydajności dla trzech metod;
https://jsperf.com/get-the-number-of-keys-in-an-object
Object.keys (). Długość
20 735 operacji na sekundę
Bardzo prosty i kompatybilny. Działa szybko, ale jest drogi, ponieważ tworzy nowy zestaw kluczy, który następnie zostaje wyrzucony.
zapętlić klucze
15 734 operacji na sekundę
Nieco wolniej, ale nigdzie w pobliżu użycia pamięci, więc prawdopodobnie lepiej, jeśli chcesz zoptymalizować pod kątem urządzeń mobilnych lub innych małych komputerów
Używanie mapy zamiast obiektu
953 839 338 operacji na sekundę
Zasadniczo mapa śledzi swój własny rozmiar, więc zwracamy tylko pole liczbowe. Daleko, znacznie szybciej niż jakakolwiek inna metoda. Jeśli masz kontrolę nad obiektem, zamień je na mapy.
źródło
Od: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
Możesz dodać go do wszystkich swoich obiektów:
Lub pojedynczy obiekt:
Przykład:
Dodane w ten sposób nie będzie wyświetlane w pętlach for..in:
Wynik:
Uwaga: nie działa w <przeglądarkach IE9.
źródło
Rozwiązałem ten problem, tworząc własną implementację podstawowej listy, która prowadzi rejestr liczby elementów przechowywanych w obiekcie. To jest bardzo proste. Coś takiego:
źródło
var i = basiclist.count
while(i--){...}
add
zastępuje stary element lub czyremove
jest wywoływany z nieistniejącym indeksem. Nie można również sprawdzić, czy lista ma podany indeks, czyundefined
jest prawidłową wartością pozycji.Możesz użyć
Object.keys(data).length
do znalezienia długości obiektu JSON zawierającego kluczowe daneźródło
Dla tych, którzy mają Ext JS 4 w swoim projekcie, możesz:
Zaletą tego jest to, że będzie działać na wszystkich przeglądarkach kompatybilnych z Ext (włącznie z IE6-IE8), jednak uważam, że czas działania nie jest lepszy niż O (n), jak w przypadku innych sugerowanych rozwiązań.
źródło
Możesz użyć:
i
źródło
OP nie określił, czy obiekt jest nodeList, jeśli tak, to możesz po prostu bezpośrednio użyć metody length . Przykład:
źródło
Jeśli powyższe jQuery nie działa, spróbuj
źródło
Object.Item
nie istniejeNie sądzę, że jest to możliwe (przynajmniej nie bez użycia elementów wewnętrznych). I nie sądzę, byś dużo zyskał, optymalizując to.
źródło
Staram się udostępnić go wszystkim takim obiektom:
źródło
Google Closure ma niezłą funkcję do tego ... goog.object.getCount (obj)
spójrz na goog.Object Documentation
źródło