2008-10-16 18 views
683

Di puedo crear un objeto así:Cómo enumerar las propiedades de un objeto JavaScript

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

¿Cuál es la mejor manera de recuperar una lista de los nombres de las propiedades? es decir, me gustaría terminar con algunas 'llaves' variables tales que:

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

Un poco fuera de tema, pero si se utiliza underscore.js: '_.keys (myJSONObject)' –

+0

Posible duplicado de [¿Cómo puedo recorrer o enumerar un objeto JavaScript?] (http: // stackoverfl ow.com/questions/684672/how-do-i-loop-through-or-enumerate-a-javascript-object) –

Respuesta

868

En los navegadores modernos (IE9 +, FF4 +, Chrome5 +, Opera12 +, Safari5 +) se puede utilizar el construido en Object.keys método:

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

reemplazar Alternativamente var getKeys con Object.prototype.keys para permitir que llame .keys() en cualquier objeto. Extender el prototipo tiene algunos efectos secundarios y no recomendaría hacerlo.

+16

Me gustaría actualizar de nuevo al efecto 'podría estar tentado de hacer esto para objetar el prototipo ... ¡pero no lo hagas! – AnthonyWJones

+3

¿Alguien querrá poner luz sobre por qué no se recomienda agregar funciones al prototipo de Objeto? – Vishwanath

+2

Esa es una pregunta completamente diferente, una búsqueda rápida aquí en stackoverflow o en Google le dará mucho que leer – ximi

230

Como se mencionó en slashnick, puede usar el constructo "for in" para iterar sobre un objeto por sus nombres de atributo. Sin embargo, estará iterando sobre todos los nombres de atributos en la cadena de prototipos del objeto. Si desea iterar solo sobre los propios atributos del objeto, puede hacer uso del método Object#hasOwnProperty(). Por lo tanto, teniendo lo siguiente.

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

Ojalá hubiera leído esto antes de la respuesta de slashnic anterior. Solo tuve que pasar 15 minutos presionando la tecla 'esc' porque el objeto tenía alrededor de un millón de propiedades, la mayoría de ellas no se usaban, y tenía una alerta en él. –

+0

Aquí hay un excelente artículo sobre el tema del propio Zakas: http://www.nczonline.net/blog/2010/07/27/determining-if-an-object-property-exists/?utm_source=feedburner&utm_medium=feed&utm_campaign= Feed: + nczonline + (NCZOnline + - + The + Official + Web + Site + de + Nicholas + C.+ Zakas) –

+3

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

27

Nota que Object.keys y otros métodos ECMAScript 5 están soportados por Firefox 4, Chrome 6, Safari 5, IE 9 y por encima.

Por ejemplo:

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

ECMAScript tabla 5 Compatibilidad: http://kangax.github.com/es5-compat-table/

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

+0

También vea las teclas() en la consola para herramientas de desarrollo de Chrome, Firebug, etc. –

+0

*** http: //markcaudill.com/index.php/2009/04/javascript-new-features-ecma5/ no encontrado * ** – Kiquenet

96

Como respondió Sam Dutton, un nuevo método para este propósito se ha introducido en ECMAScript 5th Edition. Object.keys() hará lo que quiera y es compatible con Firefox 4, Chrome 6, Safari 5 y 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.I've detailed this on my blog y produjo 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; 
    }; 
})(); 

Nota que la respuesta aceptado actualmente no incluye un cheque por hasOwnProperty() y volverá propiedades que se heredan a través de la cadena de prototipo. Tampoco da cuenta del famoso error DontEnum en Internet Explorer, donde las propiedades no enumerables en la cadena del prototipo causan propiedades declaradas localmente con el mismo nombre para heredar su atributo DontEnum.

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

EDIT: tras una reciente discusión con kangax, un contribuyente conocido a prototipo, que implementó la solución para el error DontEnum basado en el código de su función Object.forIn() encontrado here.

+0

Gran respuesta, creo que la respuesta aceptada sigue siendo la solución más efectiva, suponiendo que siempre es un dict de JSON. Este es sin duda el que se usará en otros lugares. –

+1

@David Caunt: Gracias :-) Desafortunadamente, la respuesta aceptada aún caerí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 las extensiones a 'Object.prototype'. Sin embargo, suele ser el caso que el código más corto se ve significativamente más atractivo que el código más grande y más robusto, pero el objetivo de esta respuesta es utilizar ECMAScript 5th 'Object.keys()', que se puede implementar en navegadores que no lo hacen apóyalo usando este código. La versión nativa sería aún más eficiente que esto. –

+0

Buen punto: tienes razón sobre el error. Espero que cualquier buen desarrollador pruebe los métodos nativos antes de usar sus propias implementaciones. –

8

si usted está tratando de obtener los elementos únicos, pero no las funciones a continuación, este código puede ayudarle a

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 aplicación de la HashMap y sólo quiero las llaves, "este" es el objeto hashmap que contiene las claves

7

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

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

¿Su respuesta parece similar a las ya publicadas, cualquier otra cosa para agregar? – VKen

6

Bajo navegadores que soporten JS 1.8:

[i for(i in obj)] 
13

podría hacerlo con jQuery de la siguiente manera:

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

Mozilla tiene full implementation details sobre cómo hacerlo en un navegador donde ISN' t 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 lo desee, pero posiblemente en algún tipo de archivo extensions.js en la parte superior de la pila de scripts.

+0

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

1

Basándose en la respuesta aceptada.

Si el objeto tiene propiedades que desea llamar, diga .properties() intente!

var keys = Object.keys(myJSONObject); 

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

Desde que uso underscore.js en casi todos los proyectos, me gustaría utilizar la función keys:

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

La salida del que será:

['name', 'hello'] 
+0

Es una biblioteca de conjunto de herramientas para la funcionalidad javascript de uso frecuente: http://underscorejs.org/ – schmijos

+0

Es *** buena práctica de patrones *** uso _a menudo usado javascript_ como ** underscorejs.org **? – Kiquenet

13

Objeto .getOwnPropertyNames (obj) también muestra propiedades no enumerables además de las que se muestran en 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 es útil examinarlas a veces para ver qué está sucediendo 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 la forma:

  • Object.getOwnPropertyNames y Object.keysno subir la cadena de prototipo para encontrar base
  • for in hace

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

0

Puede usar un componente reutilizable object-values para obtener todos los valores del objeto.

Ejemplo:

values({ a: 1, b: 2, c: 3 }) // => [1, 2, 3] 

Cómo funciona:

function values(object: {[any]: any}): any[] { 
    const objValues = []; 
    forEach(object, val => objValues.push(val)); 
    return objValues; 
}; 
0

El trabajo solución en mis casos y entre navegadores:

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