Jak efektywnie policzyć liczbę kluczy / właściwości obiektu w JavaScript?

Jaki jest najszybszy sposób policzenia liczby kluczy / właściwości obiektu? Czy można to zrobić bez iteracji nad obiektem? czyli bez robienia

var count = 0;
for (k in myobj) if (myobj.hasOwnProperty(k)) count++;

(Firefox dostarczył magiczną właściwość __count__, ale została ona usunięta gdzieś w okolicach wersji 4.)

Author: Luc125, 2008-09-24

19 answers

Aby to zrobić w dowolnym środowisku zgodnym z ES5, takim jak Node , Chrome, IE 9+, FF 4+ lub Safari 5+:

Object.keys(obj).length
 2045
Author: Avi Flax,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-23 12:59:37

Możesz użyć tego kodu:

if (!Object.keys) {
    Object.keys = function (obj) {
        var keys = [],
            k;
        for (k in obj) {
            if (Object.prototype.hasOwnProperty.call(obj, k)) {
                keys.push(k);
            }
        }
        return keys;
    };
}

Wtedy możesz używać tego również w starszych przeglądarkach:

var len = Object.keys(obj).length;
 142
Author: Renaat De Muynck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-22 10:31:52

Jeśli używasz podkreślenia.js możesz użyć _.rozmiar (dzięki @douwe):
_.size(obj)

Alternatywnie możesz również użyć _.klawisze , które mogą być jaśniejsze dla niektórych:
_.keys(obj).length

Gorąco polecam Underscore, jego ciasna biblioteka do robienia wielu podstawowych rzeczy. W miarę możliwości dopasowują ECMA5 i odwołują się do natywnej implementacji.

W Przeciwnym Razie popieram odpowiedź @ Avi. Edytowałem go, aby dodać link do dokumentu MDC, który zawiera metodę keys() możesz dodać do przeglądarek innych niż ECMA5.

 128
Author: studgeek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-26 22:17:10

Standardowa implementacja obiektu (ES5. 1 wewnętrzne właściwości i metody obiektu) nie wymaga {[2] } do śledzenia jego liczby kluczy/właściwości, więc nie powinno być standardowego sposobu na określenie rozmiaru Object bez jawnego lub niejawnego iterowania nad jego kluczami.

Oto więc najczęściej używane alternatywy:

1. Obiekt ECMAScript.keys ()

Object.keys(obj).length; działa poprzez wewnętrznie iterację nad kluczami, aby obliczyć tymczasowa tablica i zwraca jej długość.

  • plusy - czytelna i czysta składnia. Nie jest wymagana żadna biblioteka ani kod niestandardowy, z wyjątkiem shim, jeśli natywne wsparcie jest niedostępne]}
  • Cons - napowietrzanie pamięci spowodowane utworzeniem tablicy.

2. Rozwiązania oparte na bibliotekach

Wiele przykładów opartych na bibliotekach w innym miejscu tego tematu jest użytecznymi idiomami w kontekście ich biblioteki. Z punktu widzenia wydajności nie ma jednak nic do zyskania w porównaniu do idealnego kodu bez biblioteki, ponieważ wszystkie te metody biblioteczne faktycznie zawierają pętlę for lub ES5 Object.keys (natywne lub shimmed).

3. Optymalizacja pętli for

Najwolniejszą częścią takiej pętli for jest na ogół wywołanie .hasOwnProperty(), ze względu na wywołanie funkcji overhead. Więc kiedy chcę tylko liczbę wpisów obiektu JSON, po prostu pomijam wywołanie .hasOwnProperty(), Jeśli wiem, że żaden kod nie rozszerzył ani nie rozszerzy Object.prototype.

W przeciwnym razie Twój kod może być bardzo nieco zoptymalizowany przez tworzenie k local (var k) i użycie operatora prefix-increment (++count) zamiast postfixa.

var count = 0;
for (var k in myobj) if (myobj.hasOwnProperty(k)) ++count;

Inny pomysł polega na buforowaniu metody hasOwnProperty:

var hasOwn = Object.prototype.hasOwnProperty;
var count = 0;
for (var k in myobj) if (hasOwn.call(myobj, k)) ++count;

To, czy jest to szybsze, czy nie w danym środowisku, jest kwestią benchmarkingu. I tak można się spodziewać bardzo ograniczonego przyrostu wydajności.

 66
Author: Luc125,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-27 13:14:11

Jeśli rzeczywiście masz problem z wydajnością, sugerowałbym owinięcie wywołań, które dodają / usuwają właściwości do / z obiektu za pomocą funkcji, która również zwiększa / zmniejsza odpowiednio nazwaną (size?) nieruchomości.

Wystarczy tylko raz obliczyć początkową liczbę właściwości i przejść dalej. Jeśli nie ma rzeczywistego problemu z wydajnością, nie kłopocz się. Po prostu zawiń ten fragment kodu w funkcję getNumberOfProperties(object) i skończ z tym.

 23
Author: Confusion,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-11 18:42:43

Nie znam żadnego sposobu, aby to zrobić, jednak aby utrzymać iteracje do minimum, Możesz spróbować sprawdzić istnienie __count__ i jeśli nie istnieje (ie nie Firefox), możesz iterację nad obiektem i zdefiniować go do późniejszego użycia np:

if (myobj.__count__ === undefined) {
  myobj.__count__ = ...
}

W ten sposób każda przeglądarka obsługująca __count__ użyłaby tego, a iteracje byłyby wykonywane tylko dla tych, które tego nie robią. jeśli Liczba się zmieni, a ty nie możesz tego zrobić, zawsze możesz zrobić z niej funkcję:

if (myobj.__count__ === undefined) {
  myobj.__count__ = function() { return ... }
  myobj.__count__.toString = function() { return this(); }
}

Tędy kiedy tylko odwołasz się do myobj.__count__ funkcja uruchomi się i przeliczy.

 15
Author: Luke Bennett,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-24 09:36:59

Według AVI Flax https://stackoverflow.com/a/4889658/1047014

Object.keys(obj).length

Wykona trik dla wszystkich właściwości wyliczeniowych na Twoim obiekcie, ale aby uwzględnić również nie wyliczalne właściwości, możesz zamiast tego użyć Object.getOwnPropertyNames. Oto różnica:

var myObject = new Object();

Object.defineProperty(myObject, "nonEnumerableProp", {
  enumerable: false
});
Object.defineProperty(myObject, "enumerableProp", {
  enumerable: true
});

console.log(Object.getOwnPropertyNames(myObject).length); //outputs 2
console.log(Object.keys(myObject).length); //outputs 1

console.log(myObject.hasOwnProperty("nonEnumerableProp")); //outputs true
console.log(myObject.hasOwnProperty("enumerableProp")); //outputs true

console.log("nonEnumerableProp" in myObject); //outputs true
console.log("enumerableProp" in myObject); //outputs true

Jak wspomniano tutaj to ma taką samą obsługę przeglądarki jak Object.keys

Jednak w większości przypadków możesz nie chcieć włączać nonenumerables do tego typu operacji, ale zawsze dobrze jest wiedzieć różnica;)

 15
Author: BenderTheOffender,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:39

Do iteracji na obiekcie odpowiedzi AVI Flax.klucze (obj).długość jest poprawna dla obiektu, który nie ma powiązanych z nim funkcji

Przykład:

obj = {"lol": "what", owo: "pfft"};
Object.keys(obj).length; // should be 2

Kontra

arr = [];
obj = {"lol": "what", owo: "pfft"};
obj.omg = function(){
    _.each(obj, function(a){
        arr.push(a);
    });
};
Object.keys(obj).length; // should be 3 because it looks like this 
/* obj === {"lol": "what", owo: "pfft", omg: function(){_.each(obj, function(a){arr.push(a);});}} */

Kroki, aby tego uniknąć:

  1. Nie umieszczaj funkcji w obiekcie, w którym chcesz policzyć liczbę kluczy w

  2. Użyj oddzielnego obiektu lub utwórz nowy obiekt specjalnie dla funkcji (jeśli chcesz policzyć, ile funkcji znajduje się w pliku za pomocą Object.keys(obj).length)

Również tak użyłem modułu _ lub podkreślenia z nodejs w moim przykładzie

Dokumentacja znajduje się tutaj http://underscorejs.org/ oraz jego źródło na GitHubie i inne informacje

I wreszcie implementacja lodash https://lodash.com/docs#size

_.size(obj)

 12
Author: Belldandu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-02 11:44:15

Dla tych, którzy mają podkreślenie.js zawarte w ich projekcie można zrobić:

_({a:'', b:''}).size() // => 2

Lub styl funkcjonalny:

_.size({a:'', b:''}) // => 2
 8
Author: hakunin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-04 09:04:06

Od: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

Obiekt.defineProperty (obj, prop, deskryptor)

Możesz dodać go do wszystkich obiektów:

Object.defineProperty(Object.prototype, "length", {
    enumerable: false,
    get: function() {
        return Object.keys(this).length;
    }
});

Lub pojedynczy obiekt:

var myObj = {};
Object.defineProperty(myObj, "length", {
    enumerable: false,
    get: function() {
        return Object.keys(this).length;
    }
});

Przykład:

var myObj = {};
myObj.name  = "John Doe";
myObj.email = "[email protected]";
myObj.length; //output: 2

Dodany w ten sposób, nie będzie wyświetlany w for..in pętle:

for(var i in myObj) {
     console.log(i + ":" + myObj[i]);
}

Wyjście:

name:John Doe
email:[email protected]

Uwaga: nie działa w przeglądarkach

 6
Author: lepe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-21 03:44:11

Jak rozwiązałem ten problem to zbudowanie własnej implementacji podstawowej listy, która przechowuje zapis ile elementów jest przechowywanych w obiekcie. To bardzo proste. Coś takiego:

function BasicList()
{
   var items = {};
   this.count = 0;

   this.add = function(index, item)
   {
      items[index] = item;
      this.count++;
   }

   this.remove = function (index)
   {
      delete items[index];
      this.count--;
   }

   this.get = function(index)
   {
      if (undefined === index)
        return items;
      else
        return items[index];
   }
}
 5
Author: Click Upvote,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-18 18:09:38

Dla tych, którzy mają Ext JS 4 w swoim projekcie możesz zrobić:

Ext.Object.getSize(myobj);

Zaletą tego jest to, że będzie działać na wszystkich przeglądarkach kompatybilnych z Ext (w tym IE6-IE8), jednak uważam, że czas działania nie jest lepszy niż O (n), jak w przypadku innych sugerowanych rozwiązań.

 3
Author: Mark Rhodes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-18 16:23:26

Jak wyż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.

const map = new Map();
map.set("key", "value");
map.size; // THE fastest way
 2
Author: Flavien Volken,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-19 13:26:32

Myślę, że nie jest to możliwe(przynajmniej nie bez użycia niektórych wewnętrznych). I nie sądzę, żebyś wiele zyskała optymalizując to.

 1
Author: amix,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-24 09:05:38

Jeśli powyższy jQuery nie działa, spróbuj

$(Object.Item).length
 1
Author: codejoecode,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-02 06:03:44

Staram się UDOSTĘPNIĆ go wszystkim obiektom takim jak ten:

Object.defineProperty(Object.prototype, "length", {
get() {
    if (!Object.keys) {
        Object.keys = function (obj) {
            var keys = [],k;
            for (k in obj) {
                if (Object.prototype.hasOwnProperty.call(obj, k)) {
                    keys.push(k);
                }
            }
            return keys;
        };
    }
    return Object.keys(this).length;
},});

console.log({"Name":"Joe","Age":26}.length) //returns 2
 0
Author: Taquatech,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-14 12:51:03

Możesz użyć Object.keys(data).length, aby znaleźć długość obiektu JSON posiadającego kluczowe dane

 0
Author: Codemaker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-10 08:26:20

Zamknięcie Google ma do tego ładną funkcję... goog.obiekt.getCount (obj)

Spójrz na googa.Dokumentacja Obiektu

 -1
Author: Sebastian Perez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-13 14:04:04

Możesz użyć: Object.keys(objectName).length; & Object.values(objectName).length;

 -1
Author: Fayaz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-28 07:09:18