¿Cómo contar eficientemente el número de claves / propiedades de un objeto en JavaScript?


¿Cuál es la forma más rápida de contar el número de claves/propiedades de un objeto? Es posible hacer esto sin iterar sobre el objeto? es decir, sin hacer

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

(Firefox proporcionó una propiedad magic __count__, pero se eliminó en algún lugar alrededor de la versión 4.)

Author: Luc125, 2008-09-24

19 answers

Para hacer esto en cualquier entorno compatible con ES5, como Node , Chrome, IE 9+ , FF 4+ o 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-23 12:59:37

Puedes usar este código:

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

Entonces también puedes usar esto en navegadores antiguos:

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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-22 10:31:52

Si está utilizando Subrayado.js puedes usar _.tamaño (gracias @douwe):
_.size(obj)

Alternativamente, también puede usar _.teclas que podrían ser más claras para algunos:
_.keys(obj).length

Recomiendo encarecidamente Underscore, es una biblioteca apretada para hacer muchas cosas básicas. Siempre que sea posible, coinciden con ECMA5 y se remiten a la implementación nativa.

De lo contrario, apoyo la respuesta de @Avi. Lo edité para agregar un enlace al documento MDC que incluye el método keys() puede agregar a navegadores que no son 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-26 22:17:10

La implementación de Objetos estándar (ES5.1 Object Internal Properties and Methods) no requiere un Object para rastrear su número de claves/propiedades, por lo que no debería haber una forma estándar de determinar el tamaño de un Object sin iterar explícita o implícitamente sobre sus claves.

Así que aquí están las alternativas más utilizadas:

1. Objeto de ECMAScript.keys ()

Object.keys(obj).length; Funciona por internamente iterando sobre las claves para calcular un matriz temporal y devuelve su longitud.

  • Pros - Sintaxis legible y limpia. No se requiere biblioteca o código personalizado, excepto un shim si el soporte nativo no está disponible
  • Cons - Sobrecarga de memoria debido a la creación del array.

2. Soluciones basadas en bibliotecas

Muchos ejemplos basados en bibliotecas en otras partes de este tema son expresiones útiles en el contexto de su biblioteca. Desde el punto de vista del rendimiento, sin embargo, no hay nada que ganar comparado con un código perfecto sin biblioteca, ya que todos esos métodos de biblioteca encapsulan un bucle for o ES5 Object.keys (nativo o shimmed).

3. Optimización de un bucle for

La parte más lenta de tal bucle for es generalmente la llamada .hasOwnProperty(), debido a la sobrecarga de la llamada a la función. Así que cuando solo quiero el número de entradas de un objeto JSON, simplemente omito la llamada .hasOwnProperty() si sé que ningún código hizo ni extenderá Object.prototype.

De lo contrario, su código podría ser muy ligeramente optimizado haciendo k local (var k) y usando el operador de incremento de prefijo (++count) en lugar de postfijo.

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

Otra idea se basa en el almacenamiento en caché del método hasOwnProperty:

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

Si esto es más rápido o no en un entorno dado es una cuestión de benchmarking. De todos modos, se puede esperar una ganancia de rendimiento muy limitada.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-27 13:14:11

Si en realidad se encuentra con un problema de rendimiento, le sugeriría envolver las llamadas que agregan/eliminan propiedades al objeto con una función que también incrementa/decrementa un nombre apropiado (size?) propiedad.

Solo necesita calcular el número inicial de propiedades una vez y continuar desde allí. Si no hay un problema de rendimiento real, no se moleste. Simplemente envuelva ese bit de código en una función getNumberOfProperties(object) y termine con él.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-11 18:42:43

No estoy al tanto de ninguna manera de hacer esto, sin embargo, para mantener las iteraciones al mínimo, podría intentar verificar la existencia de __count__ y si no existe (es decir, no Firefox), entonces podría iterar sobre el objeto y definirlo para su uso posterior, por ejemplo:

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

De esta manera cualquier navegador que soporte __count__ usaría eso, y las iteraciones solo se llevarían a cabo para aquellos que no lo hacen. Si el conteo cambia y no puede hacer esto, siempre podría hacerlo una función:

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

De esta manera cada vez que haga referencia a myobj.__count__ la función se disparará y recalculará.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-24 09:36:59

Según lo declarado por Avi Flax https://stackoverflow.com/a/4889658/1047014

Object.keys(obj).length

Hará el truco para todas las propiedades enumerables en su objeto, pero para incluir también las propiedades no enumerables, puede usar Object.getOwnPropertyNames. Aquí está la diferencia:

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

Como se indica aquí {[6] } esto tiene el mismo soporte de navegador que Object.keys

Sin embargo, en la mayoría de los casos, es posible que no desee incluir los no numerables en este tipo de operaciones, pero siempre es bueno saber la diferencia ;)

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 10:31:39

Para iterar en el objeto de respuesta Avi Flax.llaves (obj).la longitud es correcta para un objeto que no tiene funciones atadas a él

Ejemplo:

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

Versus

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

Pasos para evitar esto:

  1. No ponga funciones en un objeto en el que desee contar el número de teclas en

  2. Utilice un objeto separado o cree un nuevo objeto específicamente para funciones (si desea contar cuántas funciones hay en el archivo utilizando Object.keys(obj).length)

También usé el módulo _ o underscore de nodejs en mi ejemplo

La documentación se puede encontrar aquí http://underscorejs.org / así como su fuente en github y otra información

Y finalmente una implementación de 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-02 11:44:15

Para aquellos que tienen Subrayado.js incluido en su proyecto se puede hacer:

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

O estilo funcional:

_.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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-04 09:04:06

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

Objeto.defineProperty (obj, prop, descriptor)

Puedes añadirlo a todos tus objetos:

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

O un solo objeto:

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

Ejemplo:

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

Añadido de esa manera, no se mostrará en for..in bucles:

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

Salida:

name:John Doe
email:[email protected]

Nota: no funciona en navegadores

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-21 03:44:11

Cómo he resuelto este problema es construir mi propia implementación de una lista básica que mantiene un registro de cuántos elementos se almacenan en el objeto. Es muy simple. Algo como esto:

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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-18 18:09:38

Para aquellos que tienen Ext JS 4 en su proyecto puedes hacer:

Ext.Object.getSize(myobj);

La ventaja de esto es que funcionará en todos los navegadores compatibles con Ext (IE6-IE8 incluido), sin embargo, creo que el tiempo de ejecución no es mejor que O(n), al igual que con otras soluciones sugeridas.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-08-18 16:23:26

Como se respondió anteriormente: Object.keys(obj).length

Pero: como ahora tenemos una clase real Map en ES6, yo sugeriría usarla en lugar de usar las propiedades de un objeto.

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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-19 13:26:32

No creo que esto sea posible (al menos no sin usar algunos elementos internos). Y no creo que ganarías mucho optimizando esto.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-24 09:05:38

Si jQuery anterior no funciona, intente

$(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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-02 06:03:44

Trato de hacerlo disponible para todos los objetos de esta manera:

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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-14 12:51:03

Puede usar Object.keys(data).length para encontrar la longitud del objeto JSON que tiene datos clave

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-10 08:26:20

Google Closure tiene una buena función para esto... goog.objeto.getCount (obj)

Mira a Goog.Documentación de objetos

 -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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-13 14:04:04

Puede utilizar: 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-28 07:09:18