Pregunta

¿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 magia __count__ propiedad, pero esto se eliminó en algún momento alrededor de la versión 4.)

¿Fue útil?

Solución

Para hacer esto en cualquier Entorno compatible con ES5, como Nodo, Chrome, IE 9+, Firefox 4+ o Safari 5+:

Object.keys(obj).length

Otros consejos

Podrías 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 más antiguos:

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

Si estas usando Subrayado.js puedes usar _.tamaño (gracias @douwe):
_.size(obj)

Alternativamente también puedes usar _.llaves que podría ser más claro para algunos:
_.keys(obj).length

Recomiendo ampliamente Underscore, es una biblioteca completa para hacer muchas cosas básicas.Siempre que sea posible, coinciden con ECMA5 y difieren de 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 claves () que puede agregar a navegadores que no son ECMA5.

La implementación de objeto estándar (Propiedades y métodos internos del objeto ES5.1) 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.

Estas son las alternativas más utilizadas:

1.Claves de objeto de ECMAScript ()

Object.keys(obj).length; Obras de internamente iterando sobre las claves para calcular una matriz temporal y devuelve su longitud.

  • Ventajas - Sintaxis legible y limpia.No se requiere biblioteca ni código personalizado, excepto una corrección si el soporte nativo no está disponible
  • Contras - 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 modismos útiles en el contexto de su biblioteca.Sin embargo, desde el punto de vista del rendimiento, no hay nada que ganar en comparación con un código perfecto sin biblioteca, ya que todos esos métodos de biblioteca en realidad encapsulan un bucle for o ES5. Object.keys (nativo o calzado).

3.Optimización de un bucle for

El parte más lenta de tal bucle for es generalmente el .hasOwnProperty() llamada, debido a la sobrecarga de llamada de función.Entonces, cuando solo quiero el número de entradas de un objeto JSON, simplemente me salto el .hasOwnProperty() Llame si sé que ningún código se extendió ni se extenderá. Object.prototype.

De lo contrario, su código podría optimizarse ligeramente haciendo k local (var k) y utilizando el operador de incremento de prefijo (++count) en lugar de sufijo.

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

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

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 determinado es una cuestión de evaluación comparativa.De todos modos, se puede esperar una ganancia de rendimiento muy limitada.

Si realmente se encuentra con un problema de rendimiento, sugeriría envolver las llamadas que agregan/eliminan propiedades hacia/desde el objeto con una función que también incrementa/disminuye una propiedad con el nombre apropiado (¿tamaño?).

Sólo necesitas 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 envuelve ese fragmento de código en una función. getNumberOfProperties(object) y terminar con esto.

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

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

De esta manera, cualquier navegador que admita __count__ usaría eso, y las iteraciones solo se llevarían a cabo para aquellas que no lo hagan.Si el recuento cambia y no puedes hacer esto, siempre puedes convertirlo en una función:

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

De esta manera cada vez que hagas referencia a myobj.__count__ la función se activará y volverá a calcular.

Como afirma Avi Flax https://stackoverflow.com/a/4889658/1047014

Object.keys(obj).length

funcionará para todas las propiedades enumerables en su objeto, pero para incluir también las propiedades no enumerables, puede usar el 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 dijo aquí esto tiene el mismo soporte de navegador que Object.keys

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

Para iterar en Avi Flax, la respuesta Object.keys(obj).length es correcta para un objeto que no tiene funciones vinculadas

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 coloque funciones en un objeto en el que desee contar el número de claves.

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

También sí, usé el módulo _ o guión bajo 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 variada

Y finalmente una implementación lodash. https://lodash.com/docs#size

_.size(obj)

Para aquellos que tienen Underscore.js incluido en su proyecto pueden hacer:

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

o estilo funcional:

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

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

Objeto.defineProperty(obj, prop, descriptor)

Puedes agregarlo 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 = "leaked@example.com";
myObj.length; //output: 2

Agregado de esa manera, no se mostrará en bucles for..in:

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

Producción:

name:John Doe
email:leaked@example.com

Nota:no funciona en navegadores <IE9.

como respondió arriba: Object.keys(obj).length

Pero:ya que ahora tenemos una verdadera Mapa clase en ES6, lo haría sugerir usarlo en lugar de usar las propiedades de un objeto.

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

La forma en que resolví este problema fue crear mi propia implementación de una lista básica que mantiene un registro de cuántos elementos están almacenados en el objeto.Es muy sencillo.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];
   }
}

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

Ext.Object.getSize(myobj);

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

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

Si jQuery anterior no funciona, intente

$(Object.Item).length

OP no especificó si el objeto es una lista de nodos, si lo es, simplemente puede usar longitud método en él directamente.Ejemplo:

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

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

Intento que esté disponible para todos los objetos como este:

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 Cierre tiene una buena función para esto...goog.object.getCount(obj)

mira goog.Object Documentación

Puedes usar: Object.keys(objectName).length; & Object.values(objectName).length;

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top