Domanda

Qual è il modo più veloce per contare il numero di chiavi / proprietà di un oggetto? È possibile farlo senza iterare sull'oggetto? cioè senza farlo

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

(Firefox ha fornito una proprietà __count__ magica, ma questa è stata rimossa da qualche parte intorno alla versione 4.)

È stato utile?

Soluzione

A tale scopo in qualsiasi ambiente compatibile ES5 , come Node , Chrome, IE 9+, Firefox 4+ o Safari 5+:

Object.keys(obj).length

Altri suggerimenti

È possibile utilizzare questo codice:

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;
    };
}

Quindi puoi usarlo anche nei browser più vecchi:

var len = Object.keys(obj).length;

Se si utilizza Underscore.js è possibile utilizzare _. size (grazie @douwe):
_.size(obj)

In alternativa puoi anche utilizzare _.keys che potrebbe essere più chiaro per alcuni:
_.keys(obj).length

Consiglio vivamente Underscore, è una libreria ristretta per fare molte cose di base. Ove possibile, corrispondono a ECMA5 e rimandano all'implementazione nativa.

Altrimenti sostengo la risposta di @ Avi. L'ho modificato per aggiungere un collegamento al documento MDC che include il metodo keys () che è possibile aggiungere ai browser non ECMA5.

L'implementazione standard degli oggetti ( Proprietà interne dell'oggetto ES5.1 e metodi ) non richiede un Object per tenere traccia del suo numero di chiavi / proprietà, quindi non dovrebbe esserci un modo standard per determinare la dimensione di un Object.keys(obj).length; senza iterare esplicitamente o implicitamente sulle sue chiavi.

Quindi ecco le alternative più comunemente usate:

1. Object.keys ()

di ECMAScript

Object.keys Funziona con internamente ripetendo le chiavi per calcolare un array temporaneo e restituirne la lunghezza.

  • Pro : sintassi leggibile e chiara. Nessuna libreria o codice personalizzato richiesto tranne uno shim se il supporto nativo non è disponibile
  • Contro : sovraccarico di memoria dovuto alla creazione dell'array.

2. Soluzioni basate su libreria

Molti esempi basati su librerie altrove in questo argomento sono utili modi di dire nel contesto della loro libreria. Da un punto di vista delle prestazioni, tuttavia, non c'è nulla da guadagnare rispetto a un perfetto codice no-library poiché tutti quei metodi di libreria effettivamente incapsulano un for-loop o ES5 .hasOwnProperty() (nativo o shimmed).

3. Ottimizzare un for-loop

La parte più lenta di tale for-loop è generalmente la chiamata Object.prototype, a causa dell'overhead della chiamata di funzione. Quindi, quando voglio solo il numero di voci di un oggetto JSON, salto semplicemente la k chiamata se so che nessun codice ha funzionato né estenderà var k.

Altrimenti, il tuo codice potrebbe essere leggermente ottimizzato creando ++count locale (hasOwnProperty) e utilizzando l'operatore di incremento del prefisso (<=>) anziché postfisso.

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

Un'altra idea si basa sulla memorizzazione nella cache del metodo <=>:

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

Se questo è più veloce o meno in un determinato ambiente è una questione di benchmarking. Ci si può aspettare comunque un aumento molto limitato delle prestazioni.

Se stai effettivamente riscontrando un problema di prestazioni, suggerirei di racchiudere le chiamate che aggiungono / rimuovono le proprietà da / verso l'oggetto con una funzione che incrementa / decrementa anche una proprietà (size?) opportunamente denominata.

Devi solo calcolare il numero iniziale di proprietà una volta e passare da lì. Se non c'è un vero problema di prestazioni, non preoccuparti. Basta racchiudere quel pezzetto di codice in una funzione getNumberOfProperties(object) e terminarlo.

Non sono a conoscenza di alcun modo per farlo, tuttavia per mantenere le iterazioni al minimo, potresti provare a verificare l'esistenza di __count__ e se non esiste (cioè non Firefox), potresti iterare l'oggetto e definirlo per un uso successivo, ad es.

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

In questo modo qualsiasi browser che supporti <=> lo userebbe e le iterazioni verrebbero eseguite solo per quelli che non lo fanno. Se il conteggio cambia e non puoi farlo, puoi sempre renderlo una funzione:

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

In questo modo ogni volta che fai riferimento a myobj. <=> la funzione verrà attivata e ricalcolata.

Come affermato da Avi Flax https://stackoverflow.com/a/4889658/1047014

Object.keys(obj).length

farà il trucco per tutte le proprietà enumerabili sul tuo oggetto ma per includere anche le proprietà non enumerabili puoi invece usare Object.getOwnPropertyNames. Ecco la differenza:

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

Come indicato qui questo ha lo stesso supporto del browser di Object.keys

Tuttavia, nella maggior parte dei casi, potresti non voler includere gli elementi non numerabili in questo tipo di operazioni, ma è sempre bene conoscere la differenza;)

Per iterare su Avi Flax, la risposta Object.keys (obj) .length è corretta per un oggetto che non ha funzioni legate ad esso

Esempio:

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

vs

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);});}} */

passi per evitarlo:

  1. non inserisce funzioni in un oggetto in cui si desidera contare il numero di chiavi

  2. usa un oggetto separato o crea un nuovo oggetto appositamente per le funzioni (se vuoi contare quante funzioni ci sono nel file usando Object.keys(obj).length)

anche sì, nel mio esempio ho usato il modulo _ o underscore di nodejs

la documentazione è disponibile qui http://underscorejs.org/ nonché la sua fonte su github e vari altri informazioni

E infine un'implementazione lodash https://lodash.com/docs#size

_.size(obj)

Per coloro che hanno Underscore.js incluso nel loro progetto puoi fare:

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

o stile funzionale:

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

Da: https: //developer.mozilla. org / it / docs / Web / JavaScript / Reference / Global_Objects / oggetto / defineProperty

  

Object.defineProperty (obj, prop, descrittore)

Puoi aggiungerlo a tutti i tuoi oggetti:

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

O un singolo oggetto:

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

Esempio:

var myObj = {};
myObj.name  = "John Doe";
myObj.email = "leaked@example.com";
myObj.length; //output: 2

Aggiunto in questo modo, non verrà visualizzato in for..in loops:

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

Output:

name:John Doe
email:leaked@example.com

Nota: non funziona in < Browser IE9.

come indicato sopra: Object.keys(obj).length

Ma: come abbiamo ora una vera Mappa classe in ES6, vorrei suggerire di utilizzare invece di usare le proprietà di un oggetto.

const map = new Map();
map.set("key", "value");
map.size; // THE fastest way

Il modo in cui ho risolto questo problema è costruire la mia implementazione di un elenco di base che tiene traccia di quanti elementi sono memorizzati nell'oggetto. È molto semplice. Qualcosa del genere:

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];
   }
}

Per quelli che hanno Ext JS 4 nel loro progetto puoi fare:

Ext.Object.getSize(myobj);

Il vantaggio di questo è che funzionerà su tutti i browser compatibili con Ext (IE6-IE8 incluso), tuttavia, credo che il tempo di esecuzione non sia migliore di O (n), tuttavia, come con altre soluzioni suggerite.

Puoi usare Object.keys(data).length per trovare la lunghezza dell'oggetto JSON con dati chiave

Se jQuery sopra non funziona, prova

$(Object.Item).length

OP non ha specificato se l'oggetto è un nodeList, in tal caso è possibile utilizzare direttamente il metodo lunghezza . Esempio:

buttons = document.querySelectorAll('[id=button)) {
console.log('Found ' + buttons.length + ' on the screen'); 

Non credo sia possibile (almeno non senza usare alcuni interni). E non credo che guadagneresti molto ottimizzando questo.

Provo a renderlo disponibile a tutti gli oggetti in questo modo:

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

Google Closure ha una bella funzione per questo ... goog.object.getCount (obj)

guarda goog.Object Documentation

Puoi usare:  Object.keys(objectName).length; & Object.values(objectName).length;

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top