¿Cómo enumerar las propiedades de un objeto JavaScript?


842

Digamos que creo un objeto así:

var myObject =
        {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};

¿Cuál es la mejor manera de recuperar una lista de los nombres de propiedad? es decir, me gustaría terminar con algunas 'claves' variables como:

keys == ["ircEvent", "method", "regex"]

3
Un poco fuera de tema, pero si usas underscore.js:_.keys(myJSONObject)
Endy Tjahjono

Respuestas:


1076

En los navegadores modernos (IE9 +, FF4 +, Chrome5 +, Opera12 +, Safari5 +) puede usar el método incorporado Object.keys :

var keys = Object.keys(myObject);

Lo anterior tiene un polyfill completo pero una versión simplificada es:

var getKeys = function(obj){
   var keys = [];
   for(var key in obj){
      keys.push(key);
   }
   return keys;
}

Alternativamente, reemplace var getKeyscon Object.prototype.keyspara permitirle llamar .keys()a cualquier objeto. Extender el prototipo tiene algunos efectos secundarios y no recomendaría hacerlo.


17
Me gustaría actualizar de nuevo al efecto "puede que tengas la tentación de hacer esto para objetar el prototipo ... ¡pero no lo hagas!"
AnthonyWJones

44
¿Alguien querrá aclarar, por qué no se recomienda agregar funciones al prototipo de Object?
Vishwanath

2
Esa es una pregunta completamente diferente en sí misma, una búsqueda rápida aquí en stackoverflow o en google le dará mucho para leer
Ximi

3
La for (var key in myObject) {...}técnica es útil para tiempos de ejecución de JavaScript fuera de los navegadores y V8. Por ejemplo, al pasar consultas de reducción de mapas de JavaScript a Riak, el Objectobjeto no existe, por lo que el Object.keysmétodo no está disponible.
ekillaby

19
@slashnick Su "versión simplificada" devuelve todas las propiedades en la cadena de prototipos del objeto (ya que está usando un "para ... en"), mientras que el Object.keysmétodo (ECMAScript 5.1) solo devuelve las propiedades propias del objeto. Lo veo como una distinción importante.
Martin Carel

255

Como señaló slashnick , puede usar la construcción "for in" para iterar sobre un objeto para sus nombres de atributo. Sin embargo, iterará sobre todos los nombres de atributos en la cadena de prototipos del objeto. Si desea iterar solo sobre los propios atributos del objeto, puede utilizar el método Object # hasOwnProperty () . Así teniendo lo siguiente.

for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
        /* useful code here */
    }
}

25
Desearía haber leído esto antes de la respuesta de slashnic anterior. Solo tuve que pasar 15 minutos presionando la esctecla porque el objeto tenía aproximadamente un millón de propiedades, la mayoría de ellas no se usaban, y tenía una alerta.
Mark Henderson el

Aquí hay un excelente artículo sobre el tema del propio Zakas: nczonline.net/blog/2010/07/27/…
Pablo Cabrera

44
LOL @MarkHenderson, pero la próxima vez, simplemente elimine el proceso del navegador y reinícielo en lugar de perder 15 minutos :)
JD Smith

Una función relacionada es obj.getOwnPropertyNames () - developer.mozilla.org/en-US/docs/JavaScript/Reference/…
Steve Goodman

@ MarkHenderson ¿Por qué no usarás console.log?
LasagnaAndroid

102

Como respondió Sam Dutton, se ha introducido un nuevo método para este mismo propósito en ECMAScript 5th Edition. Object.keys()hará lo que quieras y es compatible con Firefox 4 , Chrome 6, Safari 5 e IE 9 .

También puede implementar fácilmente el método en navegadores que no lo admiten. Sin embargo, algunas de las implementaciones no son totalmente compatibles con Internet Explorer. Aquí hay una solución más compatible:

Object.keys = Object.keys || (function () {
    var hasOwnProperty = Object.prototype.hasOwnProperty,
        hasDontEnumBug = !{toString:null}.propertyIsEnumerable("toString"),
        DontEnums = [ 
            'toString', 'toLocaleString', 'valueOf', 'hasOwnProperty',
            'isPrototypeOf', 'propertyIsEnumerable', 'constructor'
        ],
        DontEnumsLength = DontEnums.length;

    return function (o) {
        if (typeof o != "object" && typeof o != "function" || o === null)
            throw new TypeError("Object.keys called on a non-object");

        var result = [];
        for (var name in o) {
            if (hasOwnProperty.call(o, name))
                result.push(name);
        }

        if (hasDontEnumBug) {
            for (var i = 0; i < DontEnumsLength; i++) {
                if (hasOwnProperty.call(o, DontEnums[i]))
                    result.push(DontEnums[i]);
            }   
        }

        return result;
    };
})();

Tenga en cuenta que la respuesta actualmente aceptada no incluye una comprobación de hasOwnProperty () y devolverá las propiedades que se heredan a través de la cadena del prototipo. Tampoco tiene en cuenta el famoso error DontEnum en Internet Explorer, donde las propiedades no enumerables en la cadena del prototipo hacen que las propiedades declaradas localmente con el mismo nombre hereden su atributo DontEnum.

Implementar Object.keys () le dará una solución más robusta.

EDITAR: después de una discusión reciente con kangax , un conocido colaborador de Prototype, implementé la solución para el error DontEnum basado en el código para su Object.forIn()función que se encuentra aquí .


Gran respuesta, creo que la respuesta aceptada sigue siendo la solución más precisa y precisa, suponiendo que siempre sea una sentencia JSON. Este es ciertamente el que se debe usar en otro lugar.
David Snabel-Caunt

1
@David Caunt: Gracias :-) Desafortunadamente, la respuesta aceptada aún estaría mal del error DontEnum y nunca se sabe qué objeto JSON podría tener una cadena como "valueOf" o "constructor" como una de sus claves. También iterará sobre extensiones a Object.prototype. Sin embargo, a menudo es el caso de que el código más corto parece significativamente más atractivo que el código más grande y robusto, pero el objetivo de esta respuesta es usar ECMAScript 5th's Object.keys(), que puede implementarse en navegadores que no lo admiten con este código. La versión nativa sería aún más eficaz que esta.
Andy E

2
Muy agradable, Andy :) Me gustaría recordar, nadie parece mencionar en este hilo, que ES5 Object.keyssolo devuelve una serie de cadenas correspondientes a las propiedades enumerables de un objeto. Esto podría no ser crucial cuando se trabaja con objetos nativos (definidos por el usuario), pero debería ser muy visible con los objetos host (aunque el comportamiento de los objetos host no especificados es una historia separada, dolorosa). Para enumerar sobre TODAS las propiedades (incluidas las no enumerables), ES5 proporciona Object.getOwnPropertyNames(consulte su soporte en mi tabla de compatibilidad - kangax.github.com/es5-compat-table )
kangax

2
He integrado esta solución en es5-shim github.com/kriskowal/es5-shim/blob/master/es5-shim.js#L390
Kris Kowal

2
¿Alguien puede explicar por qué esto se implementa como Object.keys(stuff)y no stuff.keys()?
Blazemonger

32

Tenga en cuenta que Firefox 4, Chrome 6, Safari 5, IE 9 y versiones posteriores admiten Object.keys y otros métodos ECMAScript 5.

Por ejemplo:

var o = {"foo": 1, "bar": 2}; 
alert(Object.keys(o));

Tabla de compatibilidad de ECMAScript 5: http://kangax.github.com/es5-compat-table/

Descripción de nuevos métodos: http://markcaudill.com/index.php/2009/04/javascript-new-features-ecma5/


También revise las teclas () en la consola para Chrome Dev Tools, Firebug, etc.
Sam Dutton


28

Object.getOwnPropertyNames(obj)

Esta función también muestra propiedades no enumerables además de las mostradas por Object.keys(obj).

En JS, cada propiedad tiene algunas propiedades, incluida una booleana enumerable.

En general, las propiedades no enumerables son más "internas" y se usan con menos frecuencia, pero a veces es interesante analizarlas para ver qué sucede realmente.

Ejemplo:

var o = Object.create({base:0})
Object.defineProperty(o, 'yes', {enumerable: true})
Object.defineProperty(o, 'not', {enumerable: false})

console.log(Object.getOwnPropertyNames(o))
// [ 'yes', 'not' ]

console.log(Object.keys(o))
// [ 'yes' ]

for (var x in o)
    console.log(x)
// yes, base

También tenga en cuenta cómo:

  • Object.getOwnPropertyNamesy Object.keys no subas a la cadena de prototipos para encontrarbase
  • for in hace

Más información sobre la cadena de prototipos aquí: https://stackoverflow.com/a/23877420/895245


16

Soy un gran fanático de la función de volcado.

http://ajaxian.com/archives/javascript-variable-dump-in-coldfusion texto alternativo


1
+1 porque llegué aquí con la intención de construir algo similar (aunque no tan bueno).
Camilo Martin

1
netgrow.com.au/assets/files/dump/dump.zip no encontrado ¿Cómo puedo descargar JavaScript volcado?
Kiquenet

@Kiquenet cada vez que quería construir algo como esto, me conformaba con el inspector de objetos regular, si quieres que se represente en HTML, hay cosas como módulos npm . Francamente, lo que me atrapó es que quería algo mejor que lo que hay en esa imagen, pero nunca logré conceptualizarlo. Es una mierda buscar objetos en el inspector, pero la heurística para tratar de deducir el significado de los objetos arbitrarios (por ejemplo, ordenar los conjuntos de objetos en tablas con columnas) no siempre funciona en la práctica.
Camilo Martin

¿Qué pasa con Pretty Print Javascript https://j11y.io/demos/prettyprint/ ?
Kiquenet

13

Podría hacerlo con jQuery de la siguiente manera:

var objectKeys = $.map(object, function(value, key) {
  return key;
});

9

si está tratando de obtener solo los elementos pero no las funciones, entonces este código puede ayudarlo

this.getKeys = function() {

    var keys = new Array();
    for(var key in this) {

        if( typeof this[key] !== 'function') {

            keys.push(key);
        }
    }
    return keys;
}

esto es parte de mi implementación de HashMap y solo quiero las claves, "este" es el objeto hashmap que contiene las claves


8

Esto funcionará en la mayoría de los navegadores, incluso en IE8, y no se requieren bibliotecas de ningún tipo. var i es tu clave.

var myJSONObject =  {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"}; 
var keys=[];
for (var i in myJSONObject ) { keys.push(i); }
alert(keys);

2
Su respuesta parece similar a las ya publicadas, ¿hay algo más que agregar?
VKen

7

Bajo los navegadores que admiten js 1.8:

[i for(i in obj)]

7

Mozilla tiene detalles completos de implementación sobre cómo hacerlo en un navegador donde no es compatible, si eso ayuda:

if (!Object.keys) {
  Object.keys = (function () {
    var hasOwnProperty = Object.prototype.hasOwnProperty,
        hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
        dontEnums = [
          'toString',
          'toLocaleString',
          'valueOf',
          'hasOwnProperty',
          'isPrototypeOf',
          'propertyIsEnumerable',
          'constructor'
        ],
        dontEnumsLength = dontEnums.length;

    return function (obj) {
      if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) throw new TypeError('Object.keys called on non-object');

      var result = [];

      for (var prop in obj) {
        if (hasOwnProperty.call(obj, prop)) result.push(prop);
      }

      if (hasDontEnumBug) {
        for (var i=0; i < dontEnumsLength; i++) {
          if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]);
        }
      }
      return result;
    };
  })();
}

Puede incluirlo como desee, pero posiblemente en algún tipo de extensions.jsarchivo en la parte superior de su pila de scripts.


La implementación de MDN se basa en Andy E's, que ya se dio como respuesta.
outis

5

Utilizar Reflect.ownKeys()

var obj = {a: 1, b: 2, c: 3};
Reflect.ownKeys(obj) // ["a", "b", "c"]

Object.keys y Object.getOwnPropertyNames no pueden obtener propiedades no enumerables . Funciona incluso para propiedades no enumerables .

var obj = {a: 1, b: 2, c: 3};
obj[Symbol()] = 4;
Reflect.ownKeys(obj) // ["a", "b", "c", Symbol()]


4

Como uso underscore.js en casi todos los proyectos, usaría la keysfunción:

var obj = {name: 'gach', hello: 'world'};
console.log(_.keys(obj));

La salida de eso será:

['name', 'hello']

Es una biblioteca de conjunto de herramientas para la funcionalidad de JavaScript que se usa con frecuencia: underscorejs.org
schmijos

4

Sobre la base de la respuesta aceptada.

Si el objeto tiene propiedades a las que desea llamar, por ejemplo, .properties () ¡intente!

var keys = Object.keys(myJSONObject);

for (var j=0; j < keys.length; j++) {
  Object[keys[j]].properties();
}

0

La solución funciona en mis casos y en el navegador cruzado:

var getKeys = function(obj) {
    var type = typeof  obj;
    var isObjectType = type === 'function' || type === 'object' || !!obj;

    // 1
    if(isObjectType) {
        return Object.keys(obj);
    }

    // 2
    var keys = [];
    for(var i in obj) {
        if(obj.hasOwnProperty(i)) {
            keys.push(i)
        }
    }
    if(keys.length) {
        return keys;
    }

    // 3 - bug for ie9 <
    var hasEnumbug = !{toString: null}.propertyIsEnumerable('toString');
    if(hasEnumbug) {
        var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString',
            'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];

        var nonEnumIdx = nonEnumerableProps.length;

        while (nonEnumIdx--) {
            var prop = nonEnumerableProps[nonEnumIdx];
            if (Object.prototype.hasOwnProperty.call(obj, prop)) {
                keys.push(prop);
            }
        }

    }

    return keys;
};
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.