Como listar as propriedades de um objeto JavaScript?


842

Digamos que eu crie um objeto assim:

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

Qual é a melhor maneira de recuperar uma lista dos nomes de propriedades? ou seja, eu gostaria de terminar com algumas 'chaves' variáveis, tais como:

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

3
Um pouco fora de tópico, mas se você usar underscore.js:_.keys(myJSONObject)
Endy Tjahjono 28/09

Respostas:


1076

Nos navegadores modernos (IE9 +, FF4 +, Chrome5 +, Opera12 +, Safari5 +), você pode usar o método Object.keys incorporado :

var keys = Object.keys(myObject);

O acima tem um polyfill completo, mas uma versão simplificada é:

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

Como alternativa, substitua var getKeyspor Object.prototype.keyspara permitir que você chame .keys()qualquer objeto. A extensão do protótipo tem alguns efeitos colaterais e eu não recomendaria fazê-lo.


17
Gostaria de atualizar novamente para o efeito 'você pode ser tentado a fazer isso para objetar um protótipo ... mas não!'
AnthonyWJones

4
alguém quer esclarecer, por que não é recomendável adicionar funções ao protótipo de Object?
Vishwanath

2
Essa é uma questão totalmente diferente, por si própria, uma busca rápida aqui no stackoverflow ou no Google vai lhe dar muito de ler
ximi

3
A for (var key in myObject) {...}técnica é útil para tempos de execução de javascript fora dos navegadores e da V8. Por exemplo, ao passar consultas javascript para reduzir o mapa ao Riak, o Objectobjeto não existe, portanto, o Object.keysmétodo não está disponível.
ekillaby

19
@slashnick Sua "versão simplificada" retorna todas as propriedades na cadeia de protótipos do objeto (como está usando um "for ... in"), enquanto o Object.keysmétodo (ECMAScript 5.1) retorna apenas as propriedades do objeto. Eu vejo isso como uma distinção importante.
Martin Carel 16/10

255

Como slashnick apontou, você pode usar a construção "for in" para iterar sobre um objeto para seus nomes de atributo. No entanto, você estará iterando sobre todos os nomes de atributos na cadeia de protótipos do objeto. Se você deseja iterar apenas sobre os próprios atributos do objeto, poderá usar o método Object # hasOwnProperty () . Assim, tendo o seguinte.

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

25
Eu gostaria de ter lido isso antes da resposta do slashnic acima. Eu apenas tive que gastar 15 minutos pressionando a esctecla porque o objeto tinha cerca de um milhão de propriedades, a maioria delas não usada, e eu tinha um alerta.
Mark Henderson

Aqui está um excelente artigo sobre o assunto pelo próprio Zakas
Pablo Cabrera

4
LOL @MarkHenderson - mas da próxima vez, apenas matar o processo do navegador e reiniciá-lo em vez de desperdiçar 15 minutos :)
JD Smith

Uma função relacionada é obj.getOwnPropertyNames () - developer.mozilla.org/pt-BR/docs/JavaScript/Reference/…
Steve Goodman

@ MarkHenderson Por que você não usa o console.log?
LasagnaAndroid 31/03

102

Como Sam Dutton respondeu, um novo método para esse fim foi introduzido no ECMAScript 5th Edition. Object.keys()fará o que você deseja e é suportado no Firefox 4 , Chrome 6, Safari 5 e IE 9 .

Você também pode implementar muito facilmente o método em navegadores que não o suportam. No entanto, algumas das implementações existentes não são totalmente compatíveis com o Internet Explorer. Aqui está uma solução mais compatível:

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

Observe que a resposta atualmente aceita não inclui uma verificação de hasOwnProperty () e retornará propriedades herdadas pela cadeia de protótipos. Ele também não é responsável pelo famoso bug DontEnum no Internet Explorer, onde propriedades não enumeráveis ​​na cadeia de protótipos fazem com que propriedades declaradas localmente com o mesmo nome herdem seu atributo DontEnum.

A implementação de Object.keys () fornecerá uma solução mais robusta.

EDIT: após uma discussão recente com kangax , um conhecido colaborador do Prototype, implementei a solução alternativa para o bug DontEnum com base no código para sua Object.forIn()função encontrada aqui .


Ótima resposta, acho que a resposta aceita continua sendo a solução mais precisa, assumindo que seja sempre um ditado JSON. Este é certamente o único a ser usado em outro lugar.
David Snabel-Caunt 26/10/10

1
@ David Caunt: Obrigado :-) Infelizmente, a resposta aceita ainda falharia com o bug DontEnum e você nunca sabe qual objeto JSON pode ter uma string como "valueOf" ou "constructor" como uma de suas chaves. Ele também irá percorrer as extensões para Object.prototype. No entanto, é comum o código mais curto parecer significativamente mais atraente do que o código maior e mais robusto, mas o objetivo desta resposta é usar o ECMAScript 5th Object.keys(), que pode ser implementado em navegadores que não suportam esse código. A versão nativa seria ainda mais eficiente que essa.
Andy E

2
Muito bom, Andy :) Gostaria apenas de lembrar - ninguém parece mencionar neste tópico - que o ES5 Object.keysretorna apenas uma matriz de seqüências de caracteres correspondentes às propriedades enumeráveis de um objeto. Isso pode não ser crucial ao trabalhar com objetos nativos (definidos pelo usuário), mas deve ser muito visível com objetos host (embora o comportamento não especificado dos objetos host seja uma história separada - dolorosa). Para enumerar sobre ALL (incluindo não-enumeráveis) propriedades, ES5 oferece Object.getOwnPropertyNames(ver o seu apoio na minha compat mesa -. Kangax.github.com/es5-compat-table )
kangax

2
Eu já integrou esta solução em ES5-calço github.com/kriskowal/es5-shim/blob/master/es5-shim.js#L390
Kris Kowal

2
Alguém pode explicar por que isso é implementado como Object.keys(stuff)e não stuff.keys()?
Blazemonger

32

Observe que Object.keys e outros métodos do ECMAScript 5 são suportados pelo Firefox 4, Chrome 6, Safari 5, IE 9 e superior.

Por exemplo:

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

Tabela de compatibilidade do ECMAScript 5: http://kangax.github.com/es5-compat-table/

Descrição dos novos métodos: http://markcaudill.com/index.php/2009/04/javascript-new-features-ecma5/


Verifique também as teclas () no console do Chrome Dev Tools, Firebug etc.
Sam Dutton


28

Object.getOwnPropertyNames(obj)

Essa função também mostra propriedades não enumeráveis, além daquelas mostradas por Object.keys(obj) .

Em JS, toda propriedade possui algumas propriedades, incluindo um valor booleano enumerable .

Em geral, propriedades não enumeráveis ​​são mais "internas" e menos usadas, mas é interessante analisá-las algumas vezes para ver o que realmente está acontecendo.

Exemplo:

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

Observe também como:

  • Object.getOwnPropertyNamese Object.keys não suba a cadeia de protótipos para encontrarbase
  • for in faz

Mais sobre a cadeia de protótipos aqui: https://stackoverflow.com/a/23877420/895245


16

Eu sou um grande fã da função de despejo.

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


1
+1 porque cheguei aqui com a intenção de criar algo semelhante (embora não tão bom).
Camilo Martin

1
netgrow.com.au/assets/files/dump/dump.zip não encontrado Como baixar o javascript do dump?
26517 Kiquenet

@Kiquenet toda vez que eu queria criar algo assim, eu me contentava com o inspetor de objetos regular, se você quiser que seja renderizado em HTML, existem coisas como módulos npm . Francamente, o que me deixou preso é que eu queria algo melhor do que o que está nessa imagem, mas nunca consegui conceituá-la. É uma merda procurar objetos no inspetor, mas as heurísticas para tentar deduzir o significado de objetos arbitrários (por exemplo, classificar matrizes de objetos em tabelas com colunas) nem sempre funcionam na prática.
Camilo Martin

O que é o Pretty Print Javascript https://j11y.io/demos/prettyprint/ ?
Kiquenet 4/17

13

Poderia fazê-lo com jQuery da seguinte maneira:

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

9

se você está tentando obter apenas os elementos, mas não as funções, esse código pode ajudá-lo

this.getKeys = function() {

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

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

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

isso faz parte da minha implementação do HashMap e eu quero apenas as chaves, "this" é o objeto hashmap que contém as chaves


8

Isso funcionará na maioria dos navegadores, mesmo no IE8, e nenhuma biblioteca de qualquer tipo é necessária. var i é sua chave.

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

2
Sua resposta parece semelhante às já postadas, mais alguma coisa a acrescentar?
VKen 10/10

7

Em navegadores que suportam js 1.8:

[i for(i in obj)]

7

A Mozilla tem detalhes completos de implementação sobre como fazê-lo em um navegador onde não é suportado, se isso ajudar:

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

Você pode incluí-lo como quiser, mas possivelmente em algum tipo de extensions.jsarquivo na parte superior da sua pilha de scripts.


A implementação do MDN é baseada no Andy E, que já foi dado como resposta.
out 23/07

5

Usar Reflect.ownKeys()

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

Object.keys e Object.getOwnPropertyNames não podem obter propriedades não enumeráveis . Está funcionando mesmo para propriedades não enumeráveis .

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


4

Desde que eu uso underscore.js em quase todos os projetos, usaria a keysfunção:

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

A saída disso será:

['name', 'hello']

É uma biblioteca de conjuntos de ferramentas para a funcionalidade javascript frequentemente usada: underscorejs.org
schmijos

4

Com base na resposta aceita.

Se o objeto tiver propriedades que você deseja chamar, digamos .properties (), tente!

var keys = Object.keys(myJSONObject);

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

0

A solução funciona nos meus casos e no 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;
};
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.