Jak wyświetlić właściwości obiektu JavaScript?

842

Powiedzmy, że tworzę obiekt w ten sposób:

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

Jaki jest najlepszy sposób na odzyskanie listy nazw nieruchomości? tzn. chciałbym skończyć z pewnymi zmiennymi „kluczami”, takimi jak:

keys == ["ircEvent", "method", "regex"]
johnstok
źródło
3
Trochę poza tematem, ale jeśli używasz underscore.js:_.keys(myJSONObject)
Endy Tjahjono 28.09.2013

Odpowiedzi:

1076

W nowoczesnych przeglądarkach (IE9 +, FF4 +, Chrome5 +, Opera12 +, Safari5 +) możesz użyć wbudowanej metody Object.keys :

var keys = Object.keys(myObject);

Powyższe ma pełne wypełnienie, ale uproszczoną wersją jest:

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

Ewentualnie wymienić var getKeysz Object.prototype.keysco pozwala zadzwonić .keys()na dowolny obiekt. Rozszerzenie prototypu ma pewne skutki uboczne i nie poleciłbym tego.

slashnick
źródło
17
Chciałbym zaktualizować ponownie, aby „kusiło cię zrobienie tego, by sprzeciwić się prototypowi ... ale nie rób tego!”
AnthonyWJones
4
czy ktoś chce zapalić światło, dlaczego nie zaleca się dodawania funkcji do prototypu Object?
Vishwanath,
2
To zupełnie inne pytanie samo w sobie, szybkie wyszukiwanie tutaj na stackoverflow lub w Google da ci dużo do przeczytania
Ximi
3
Ta for (var key in myObject) {...}technika jest przydatna w środowiskach uruchomieniowych javascript poza przeglądarkami i wersją V8. Na przykład, gdy przekazujemy zapytania Rivascript zmniejszające mapę do Riaka, Objectobiekt nie istnieje, więc Object.keysmetoda nie jest dostępna.
ekillaby
19
@slashnick Twoja „wersja uproszczona” zwraca wszystkie właściwości w łańcuchu prototypów obiektu (ponieważ używa „for ... in”), podczas gdy Object.keysmetoda (ECMAScript 5.1) zwraca tylko własne właściwości obiektu. Uważam to za ważne rozróżnienie.
Martin Carel
255

Jak wskazał slashnick , możesz użyć konstrukcji „for in”, aby iterować obiekt po nazwach atrybutów. Będziesz jednak iterował wszystkie nazwy atrybutów w łańcuchu prototypów obiektu. Jeśli chcesz iterować tylko nad własnymi atrybutami obiektu, możesz skorzystać z metody Object # hasOwnProperty () . Zatem mając następujące.

for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
        /* useful code here */
    }
}
Pablo Cabrera
źródło
25
Chciałbym przeczytać to przed powyższą odpowiedzią slashnic. Po prostu musiałem spędzić 15 minut, przytrzymując escklawisz, ponieważ obiekt miał około miliona właściwości, z których większość nie była używana, i otrzymałem alert.
Mark Henderson
Oto znakomity artykuł na ten temat autorstwa samego Zakasa: nczonline.net/blog/2010/07/27/…
Pablo Cabrera
4
LOL @ MarkHenderson - ale następnym razem po prostu zabij proces przeglądarki i uruchom ją ponownie zamiast marnować 15 minut :)
JD Smith
Pokrewną funkcją jest obj.getOwnPropertyNames () - developer.mozilla.org/en-US/docs/JavaScript/Reference/…
Steve Goodman
@MarkHenderson Dlaczego nie użyjesz console.log?
LasagnaAndroid
102

Jak odpowiedział Sam Dutton, w ECMAScript 5th Edition wprowadzono nową metodę do tego właśnie celu. Object.keys()zrobi co chcesz i jest obsługiwany w Firefox 4 , Chrome 6, Safari 5 i IE 9 .

Możesz także bardzo łatwo zaimplementować tę metodę w przeglądarkach, które jej nie obsługują. Jednak niektóre implementacje nie są w pełni kompatybilne z programem Internet Explorer. Oto bardziej kompatybilne rozwiązanie:

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

Zauważ, że obecnie akceptowana odpowiedź nie obejmuje sprawdzenia hasOwnProperty () i zwróci właściwości, które są dziedziczone w łańcuchu prototypów. Nie uwzględnia również słynnego błędu DontEnum w programie Internet Explorer, w którym właściwości niepoliczalne w łańcuchu prototypów powodują, że lokalnie zadeklarowane właściwości o tej samej nazwie dziedziczą ich atrybut DontEnum.

Implementacja Object.keys () zapewni bardziej niezawodne rozwiązanie.

EDYCJA: po niedawnej dyskusji z Kangaxem , znanym współpracownikiem Prototypu, zaimplementowałem obejście błędu DontEnum na podstawie kodu jego Object.forIn()funkcji znalezionej tutaj .

Andy E.
źródło
Świetna odpowiedź, myślę, że zaakceptowana odpowiedź pozostaje najdokładniejszym i najdokładniejszym rozwiązaniem, zakładając, że jest to zawsze dyktat JSON. Z pewnością można go użyć w innym miejscu.
David Snabel-Caunt
1
@David Caunt: Dzięki :-) Niestety, zaakceptowana odpowiedź nadal byłaby błędna dla błędu DontEnum i nigdy nie wiadomo, który obiekt JSON może mieć ciąg znaków „valueOf” lub „konstruktor” jako jeden z jego kluczy. Będzie również iterować po rozszerzeniach do Object.prototype. Często zdarza się jednak, że krótszy kod wygląda znacznie atrakcyjniej niż większy, bardziej solidny kod, ale celem tej odpowiedzi jest użycie ECMAScript 5th Object.keys(), który można zaimplementować w przeglądarkach, które nie obsługują go za pomocą tego kodu. Wersja natywna byłaby jeszcze bardziej wydajna niż ta.
Andy E
2
Bardzo fajnie, Andy :) Chciałbym tylko przypomnieć - chyba nikt nie wspomina w tym wątku - że ES5 Object.keyszwraca tylko tablicę ciągów odpowiadających wyliczalnym właściwościom obiektu. Może to nie mieć kluczowego znaczenia podczas pracy z obiektami natywnymi (zdefiniowanymi przez użytkownika), ale powinno być bardzo widoczne w przypadku obiektów hosta (chociaż nieokreślone zachowanie obiektów hosta jest osobną - bolesną - historią). Aby wyliczyć wszystkie WSZYSTKIE (w tym niepoliczalne) właściwości, ES5 zapewnia Object.getOwnPropertyNames(zobacz jego obsługę w mojej tabeli kompatybilności - kangax.github.com/es5-compat-table )
kangax
2
Zintegrowałem to rozwiązanie z es5- shim github.com/kriskowal/es5-shim/blob/master/es5-shim.js#L390
Kris Kowal
2
Czy ktoś może wyjaśnić, dlaczego jest to realizowane jako Object.keys(stuff)nie stuff.keys()?
Blazemonger,
32

Pamiętaj, że Object.keys i inne metody ECMAScript 5 są obsługiwane przez Firefox 4, Chrome 6, Safari 5, IE 9 i nowsze wersje.

Na przykład:

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

Tabela zgodności ECMAScript 5: http://kangax.github.com/es5-compat-table/

Opis nowych metod: http://markcaudill.com/index.php/2009/04/javascript-new-features-ecma5/

Sam Dutton
źródło
Sprawdź także keys () w konsoli dla Chrome Dev Tools, Firebug itp.
Sam Dutton,
28

Object.getOwnPropertyNames(obj)

Ta funkcja pokazuje także właściwości niepoliczalne, oprócz właściwości pokazanych przez Object.keys(obj).

W JS każda właściwość ma kilka właściwości, w tym wartość logiczną enumerable.

Ogólnie rzecz biorąc, niepoliczalne właściwości są bardziej „wewnętrzne” i rzadziej używane, ale czasem warto je zaglądać, aby zobaczyć, co się naprawdę dzieje.

Przykład:

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

Zwróć również uwagę, jak:

  • Object.getOwnPropertyNamesi Object.keys nie wchodź do łańcucha prototypów, aby znaleźćbase
  • for in robi

Więcej informacji o łańcuchu prototypów tutaj: https://stackoverflow.com/a/23877420/895245

Ciro Santilli
źródło
16

Jestem wielkim fanem funkcji zrzutu.

http://ajaxian.com/archives/javascript-variable-dump-in-coldfusion alternatywny tekst

Matt
źródło
1
+1, ponieważ przybyłem tutaj z zamiarem zbudowania czegoś podobnego (choć nie tak dobrego).
Camilo Martin
1
netgrow.com.au/assets/files/dump/dump.zip nie znaleziono Jak mogę pobrać zrzut javascript?
Kiquenet
@Kiquenet za każdym razem, gdy chciałem zbudować coś takiego, zadowalam się zwykłym inspektorem obiektów, jeśli chcesz, aby to renderowane w HTML zawierało takie rzeczy jak moduły npm . Szczerze mówiąc, utknąłem w tym, że chciałem czegoś lepszego niż to, co jest na tym obrazie, ale nigdy nie udało mi się go konceptualizować. Gówno jest przeglądać obiekty w inspektorze, ale heurystyka próbująca wydedukować znaczenie z dowolnych obiektów (np. Sortowanie tablic obiektów do tabel z kolumnami) nie zawsze działa w praktyce.
Camilo Martin
Co z Pretty Print Javascript https://j11y.io/demos/prettyprint/ ?
Kiquenet,
13

Można to zrobić za pomocą jQuery w następujący sposób:

var objectKeys = $.map(object, function(value, key) {
  return key;
});
sbonami
źródło
9

jeśli próbujesz uzyskać tylko elementy, ale nie funkcje, ten kod może ci pomóc

this.getKeys = function() {

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

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

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

jest to część mojej implementacji HashMap i chcę tylko kluczy, „to” to obiekt hashmap zawierający klucze

zeacuss
źródło
8

Działa to w większości przeglądarek, nawet w IE8, i nie są wymagane żadne biblioteki. var i jest twoim kluczem.

var myJSONObject =  {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"}; 
var keys=[];
for (var i in myJSONObject ) { keys.push(i); }
alert(keys);
qwerty_jones
źródło
2
Twoja odpowiedź wydaje się podobna do tych, które już opublikowano, coś jeszcze do dodania?
VKen
7

W przeglądarkach obsługujących js 1.8:

[i for(i in obj)]
Rix Beck
źródło
7

Mozilla ma pełne szczegóły implementacji, jak to zrobić w przeglądarce, która nie jest obsługiwana, jeśli to pomaga:

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

Możesz dołączyć go, jak chcesz, ale być może w jakimś extensions.jspliku na górze stosu skryptów.

Kristofer Sommestad
źródło
Implementacja MDN oparta jest na Andach E., które już podano jako odpowiedź.
poza
5

Posługiwać się Reflect.ownKeys()

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

Object.keys i Object.getOwnPropertyNames nie może dostać zakaz przeliczalna właściwości. Działa nawet w przypadku właściwości niepoliczalnych .

var obj = {a: 1, b: 2, c: 3};
obj[Symbol()] = 4;
Reflect.ownKeys(obj) // ["a", "b", "c", Symbol()]
selmansamet
źródło
4

Ponieważ używam underscore.js w prawie każdym projekcie, użyłbym keysfunkcji:

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

Wynikiem będzie:

['name', 'hello']
schmijos
źródło
Jest to biblioteka
zestawów
4

Opierając się na przyjętej odpowiedzi.

Jeśli obiekt ma właściwości, które chcesz nazwać, powiedz .properties () spróbuj!

var keys = Object.keys(myJSONObject);

for (var j=0; j < keys.length; j++) {
  Object[keys[j]].properties();
}
Sydwell
źródło
0

Rozwiązanie działa w moich przypadkach i w różnych przeglądarkach:

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;
};
Christian Nguyen
źródło