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"]

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.


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 */
    }
}

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 .


Ś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
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/


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


16

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

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


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

2
Twoja odpowiedź wydaje się podobna do tych, które już opublikowano, coś jeszcze do dodania?
VKen


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.


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()]


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']

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

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;
};
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.