Come elencare le proprietà di un oggetto JavaScript?


842

Di 'che creo un oggetto così:

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

Qual è il modo migliore per recuperare un elenco dei nomi delle proprietà? cioè vorrei finire con alcune 'chiavi' variabili tali che:

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

3
Un po 'fuori tema, ma se usi underscore.js:_.keys(myJSONObject)
Endy Tjahjono,

Risposte:


1076

Nei browser moderni (IE9 +, FF4 +, Chrome5 +, Opera12 +, Safari5 +) è possibile utilizzare il metodo Object.keys incorporato :

var keys = Object.keys(myObject);

Quanto sopra ha un polifill completo ma una versione semplificata è:

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

In alternativa, sostituire var getKeyscon Object.prototype.keysper consentire di chiamare .keys()qualsiasi oggetto. L'estensione del prototipo ha alcuni effetti collaterali e non consiglierei di farlo.


17
Vorrei aggiornare nuovamente l'effetto "potresti essere tentato di fare questo per obiettare il prototipo ... ma non farlo!"
AnthonyWJones,

4
qualcuno vorrà accendere la luce, perché non è consigliabile aggiungere funzioni al prototipo di Object?
Vishwanath,

2
Questa è una domanda completamente diversa da sola, una rapida ricerca qui su StackOverflow o su Google ti darà molto da leggere
ximi

3
La for (var key in myObject) {...}tecnica è utile per i runtime javascript al di fuori dei browser e V8. Ad esempio, quando si passano le query di riduzione della mappa javascript in Riak l' Objectoggetto non esiste, quindi il Object.keysmetodo non è disponibile.
ekillaby,

19
@slashnick La tua "versione semplificata" restituisce tutte le proprietà nella catena di prototipi dell'oggetto (poiché utilizza un "per ... in"), mentre il Object.keysmetodo (ECMAScript 5.1) restituisce solo le proprietà dell'oggetto. Lo vedo come una distinzione importante.
Martin Carel,

255

Come ha sottolineato Slashnick , puoi usare il costrutto "for in" per scorrere su un oggetto per i nomi dei suoi attributi. Tuttavia, ripeterai tutti i nomi degli attributi nella catena di prototipi dell'oggetto. Se si desidera iterare solo sugli attributi dell'oggetto, è possibile utilizzare il metodo Object # hasOwnProperty () . Avendo così il seguente.

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

25
Vorrei averlo letto prima della risposta di Slashnic sopra. Ho dovuto passare solo 15 minuti a tenere premuto il esctasto perché l'oggetto aveva circa un milione di proprietà, molte delle quali non utilizzate, e avevo un avviso.
Mark Henderson,

Ecco un eccellente articolo sull'argomento dello stesso Zakas
Pablo Cabrera,

4
LOL @MarkHenderson - ma la prossima volta, basta terminare il processo del browser e riavviarlo invece di perdere 15 minuti :)
JD Smith

Una funzione correlata è obj.getOwnPropertyNames () - developer.mozilla.org/en-US/docs/JavaScript/Reference/…
Steve Goodman,

@MarkHenderson Perché non usi console.log?
LasagnaAndroid

102

Come ha risposto Sam Dutton, un nuovo metodo proprio per questo scopo è stato introdotto in ECMAScript 5th Edition. Object.keys()farà quello che vuoi ed è supportato in Firefox 4 , Chrome 6, Safari 5 e IE 9 .

Puoi anche implementare molto facilmente il metodo nei browser che non lo supportano. Tuttavia, alcune delle implementazioni disponibili non sono completamente compatibili con Internet Explorer. Ecco una soluzione più compatibile:

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

Si noti che la risposta attualmente accettata non include un controllo per hasOwnProperty () e restituirà proprietà ereditate attraverso la catena di prototipi. Inoltre, non tiene conto del famoso bug DontEnum in Internet Explorer in cui le proprietà non enumerabili nella catena di prototipi fanno sì che le proprietà dichiarate localmente con lo stesso nome ereditino l'attributo DontEnum.

L'implementazione di Object.keys () ti darà una soluzione più solida.

EDIT: a seguito di una recente discussione con kangax , noto collaboratore di Prototype, ho implementato la soluzione alternativa per il bug DontEnum basato sul codice per la sua Object.forIn()funzione trovata qui .


Ottima risposta, penso che la risposta accettata rimanga la soluzione accurata più performante, supponendo che sia sempre un dict JSON. Questo è sicuramente quello da usare altrove.
David Snabel-Caunt,

1
@David Caunt: Grazie :-) Sfortunatamente, la risposta accettata rimarrebbe comunque un fallo del bug DontEnum e non si sa mai quale oggetto JSON potrebbe avere una stringa come "valueOf" o "costruttore" come una delle sue chiavi. Esaminerà anche le estensioni a Object.prototype. Spesso, tuttavia, il codice più breve sembra significativamente più attraente rispetto al codice più grande e più robusto, ma il punto di questa risposta è utilizzare ECMAScript 5th Object.keys(), che può essere implementato nei browser che non lo supportano utilizzando questo codice. La versione nativa sarebbe ancora più performante di questa.
Andy E,

2
Molto bello, Andy :) Vorrei solo ricordare - nessuno sembra menzionare in questo thread - che ES5 Object.keysrestituisce solo una matrice di stringhe corrispondenti alle proprietà enumerabili di un oggetto. Questo potrebbe non essere cruciale quando si lavora con oggetti nativi (definiti dall'utente), ma dovrebbe essere molto visibile con oggetti host (sebbene il comportamento di oggetti host non specificato sia una storia separata - dolorosa). Per enumerare TUTTE (incluse le proprietà non enumerabili), ES5 fornisce Object.getOwnPropertyNames(vedi il suo supporto nella mia tabella compatibilità - kangax.github.com/es5-compat-table )
kangax

2
Ho integrato questa soluzione in es5-shim github.com/kriskowal/es5-shim/blob/master/es5-shim.js#L390
Kris Kowal

2
Qualcuno può spiegare perché questo è implementato come Object.keys(stuff)e non stuff.keys()?
Blazemonger,

32

Si noti che Object.keys e altri metodi ECMAScript 5 sono supportati da Firefox 4, Chrome 6, Safari 5, IE 9 e versioni successive.

Per esempio:

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

Tabella di compatibilità ECMAScript 5: http://kangax.github.com/es5-compat-table/

Descrizione di nuovi metodi: http://markcaudill.com/index.php/2009/04/javascript-new-features-ecma5/


Controlla anche le chiavi () nella console per Chrome Dev Tools, Firebug, ecc.
Sam Dutton,


28

Object.getOwnPropertyNames(obj)

Questa funzione mostra anche proprietà non enumerabili oltre a quelle mostrate da Object.keys(obj).

In JS, ogni proprietà ha alcune proprietà, tra cui un valore booleano enumerable.

In generale, le proprietà non enumerabili sono più "interne" e meno utilizzate, ma è perspicace guardarle qualche volta per vedere cosa sta realmente succedendo.

Esempio:

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

Nota anche come:

  • Object.getOwnPropertyNamese Object.keys non salire sulla catena di prototipi per trovarebase
  • for in fa

Maggiori informazioni sulla catena di prototipi qui: https://stackoverflow.com/a/23877420/895245


16

1
+1 perché sono arrivato qui con l'intenzione di costruire qualcosa di simile (anche se non altrettanto buono).
Camilo Martin,

1
netgrow.com.au/assets/files/dump/dump.zip non trovato Come posso scaricare dump javascript?
Kiquenet,

@Kiquenet ogni volta che volevo creare qualcosa del genere mi accontento del normale ispettore oggetti, se vuoi che sia reso in HTML ci sono cose come i moduli npm . Francamente ciò che mi ha bloccato è che volevo qualcosa di meglio di quello che c'è su quell'immagine ma non sono mai riuscito a concettualizzarlo. È merdoso sfogliare gli oggetti nell'ispettore ma l'euristica per cercare di dedurre significato da oggetti arbitrari (ad esempio, ordinare le matrici di oggetti in tabelle con colonne) non sempre funziona nella pratica.
Camilo Martin,

Che cos'è Pretty Print Javascript https://j11y.io/demos/prettyprint/ ?
Kiquenet,

13

Potrebbe farlo con jQuery come segue:

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

9

se stai cercando di ottenere solo gli elementi ma non le funzioni, questo codice può aiutarti

this.getKeys = function() {

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

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

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

questo fa parte della mia implementazione di HashMap e voglio solo le chiavi, "questo" è l'oggetto hashmap che contiene le chiavi


8

Funzionerà nella maggior parte dei browser, anche in IE8, e non sono necessarie librerie di alcun tipo. var è la tua chiave.

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

2
La tua risposta sembra simile a quelle già pubblicate, qualcos'altro da aggiungere?
VKen,

7

Sotto i browser che supportano js 1.8:

[i for(i in obj)]

7

Mozilla ha tutti i dettagli di implementazione su come farlo in un browser in cui non è supportato, se ciò aiuta:

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

Potresti includerlo come preferisci, ma probabilmente in una sorta di extensions.jsfile nella parte superiore dello stack di script.


L'implementazione di MDN si basa su Andy E, che è già stata fornita come risposta.
uscita il

5

Uso Reflect.ownKeys()

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

Object.keys e Object.getOwnPropertyNames non possono ottenere proprietà non enumerabili . Funziona anche per proprietà non enumerabili .

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


4

Dato che uso underscore.js in quasi tutti i progetti, utilizzerei la keysfunzione:

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

Il risultato sarà:

['name', 'hello']

È una libreria di set di strumenti per la funzionalità javascript spesso usata: underscorejs.org
schmijos

4

Sulla base della risposta accettata.

Se l'oggetto ha proprietà che vuoi chiamare, dì .properties () prova!

var keys = Object.keys(myJSONObject);

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

0

La soluzione funziona sui miei casi e sul mio browser:

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;
};
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.