Bagaimana cara mendaftar properti dari objek JavaScript?

842

Katakanlah saya membuat objek dengan demikian:

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

Apa cara terbaik untuk mengambil daftar nama properti? yaitu saya ingin berakhir dengan beberapa 'kunci' variabel sehingga:

keys == ["ircEvent", "method", "regex"]
Johnstok
sumber
3
Topik yang agak aneh, tetapi jika Anda menggunakan underscore.js:_.keys(myJSONObject)
Endy Tjahjono

Jawaban:

1076

Di browser modern (IE9 +, FF4 +, Chrome5 +, Opera12 +, Safari5 +) Anda dapat menggunakan metode Object.keys bawaan :

var keys = Object.keys(myObject);

Di atas memiliki polyfill lengkap tetapi versi yang disederhanakan adalah:

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

Atau ganti var getKeysdengan Object.prototype.keysuntuk memungkinkan Anda memanggil .keys()objek apa pun. Memperluas prototipe memiliki beberapa efek samping dan saya tidak akan merekomendasikan melakukannya.

slashnick
sumber
17
Saya akan memperbarui lagi dengan efek 'Anda mungkin tergoda untuk melakukan ini ke objek prototipe ... tapi jangan!'
AnthonyWJones
4
akan ada yang mau menjelaskan, mengapa tidak disarankan untuk menambahkan fungsi ke prototipe Obyek?
Vishwanath
2
Itu pertanyaan yang sama sekali berbeda pada itu sendiri, pencarian cepat di sini di stackoverflow atau di Google akan memberi Anda banyak untuk dibaca
ximi
3
The for (var key in myObject) {...}Teknik ini berguna untuk runtimes javascript luar browser dan V8. Misalnya, ketika meneruskan permintaan pengurangan peta javascript ke Riak Objectobjek tidak ada, jadi Object.keysmetode ini tidak tersedia.
ekillaby
19
@ slashnick "Versi yang disederhanakan" Anda mengembalikan semua properti dalam rantai prototipe objek (karena menggunakan "untuk ... dalam"), sedangkan metode (ECMAScript 5.1) Object.keyshanya mengembalikan properti objek itu sendiri. Saya melihatnya sebagai perbedaan penting.
Martin Carel
255

Seperti yang ditunjukkan slashnick , Anda dapat menggunakan konstruk "for in" untuk beralih pada objek untuk nama atributnya. Namun Anda akan mengulangi semua nama atribut dalam rantai prototipe objek. Jika Anda ingin hanya mengulangi atribut objek itu sendiri, Anda dapat menggunakan metode Object # hasOwnProperty () . Dengan demikian memiliki yang berikut.

for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
        /* useful code here */
    }
}
Pablo Cabrera
sumber
25
Saya berharap saya telah membaca ini sebelum jawaban slashnic di atas. Saya hanya perlu menghabiskan 15 menit untuk menahan esckunci karena objek itu memiliki sekitar satu juta properti, kebanyakan dari mereka tidak digunakan, dan saya memiliki peringatan tentang itu.
Mark Henderson
Berikut ini adalah artikel yang sangat baik tentang masalah ini oleh Zakas sendiri: nczonline.net/blog/2010/07/27/…
Pablo Cabrera
4
LOL @MarkHenderson - tetapi lain kali, matikan saja proses peramban dan nyalakan kembali alih-alih menghabiskan waktu 15 menit :)
JD Smith
Fungsi terkait adalah obj.getOwnPropertyNames () - developer.mozilla.org/en-US/docs/JavaScript/Reference/…
Steve Goodman
@MarkHenderson Mengapa Anda tidak menggunakan console.log?
LasagnaAndroid
102

Sebagaimana Sam Dutton menjawab, metode baru untuk tujuan ini telah diperkenalkan dalam ECMAScript Edisi ke-5. Object.keys()akan melakukan apa yang Anda inginkan dan didukung di Firefox 4 , Chrome 6, Safari 5 dan IE 9 .

Anda juga dapat dengan mudah mengimplementasikan metode di browser yang tidak mendukungnya. Namun, beberapa implementasi di luar sana tidak sepenuhnya kompatibel dengan Internet Explorer. Inilah solusi yang lebih kompatibel:

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

Perhatikan bahwa jawaban yang saat ini diterima tidak termasuk cek untuk hasOwnProperty () dan akan mengembalikan properti yang diwarisi melalui rantai prototipe. Itu juga tidak memperhitungkan bug DontEnum yang terkenal di Internet Explorer di mana properti yang tidak dapat dihitung pada rantai prototipe menyebabkan properti yang dideklarasikan secara lokal dengan nama yang sama untuk mewarisi atribut DontEnum mereka.

Menerapkan Object.keys () akan memberi Anda solusi yang lebih kuat.

EDIT: mengikuti diskusi baru-baru ini dengan kangax , kontributor terkenal untuk Prototipe, saya mengimplementasikan solusi untuk bug DontEnum berdasarkan kode untuk Object.forIn()fungsinya yang ditemukan di sini .

Andy E
sumber
Jawaban yang bagus, saya pikir jawaban yang diterima tetap merupakan solusi akurat yang paling berkinerja, dengan asumsi bahwa itu selalu merupakan dikt JSON. Ini tentunya yang digunakan di tempat lain.
David Snabel-Caunt
1
@ David Caunt: Terima kasih :-) Sayangnya, jawaban yang diterima masih akan jatuh dari bug DontEnum dan Anda tidak pernah tahu objek JSON apa yang mungkin memiliki string seperti "valueOf" atau "constructor" sebagai salah satu kuncinya. Ini juga akan beralih ke ekstensi ke Object.prototype. Namun, sering terjadi bahwa kode yang lebih pendek terlihat jauh lebih menarik daripada kode yang lebih besar dan lebih kuat, tetapi inti dari jawaban ini adalah menggunakan ECMAScript 5 Object.keys(), yang dapat diimplementasikan di browser yang tidak mendukungnya menggunakan kode ini. Versi asli akan lebih performan daripada ini.
Andy E
2
Sangat bagus, Andy :) Saya hanya ingin mengingatkan - sepertinya tidak ada yang menyebutkan di utas ini - bahwa ES5 Object.keyshanya mengembalikan array string yang sesuai dengan properti enumerable dari suatu objek. Ini mungkin tidak penting ketika bekerja dengan objek asli (yang ditentukan pengguna), tetapi harus sangat terlihat dengan objek host (meskipun perilaku objek host yang tidak ditentukan adalah cerita yang terpisah - menyakitkan -). Untuk menghitung lebih dari SEMUA properti (termasuk non-enumerable), ES5 menyediakan Object.getOwnPropertyNames(lihat dukungannya di tabel compat. - kangax.github.com/es5-compat-table )
kangax
2
Saya telah mengintegrasikan solusi ini ke es5-shim github.com/kriskowal/es5-shim/blob/master/es5-shim.js#L390
Kris Kowal
2
Adakah yang bisa menjelaskan mengapa ini diterapkan Object.keys(stuff)dan tidak stuff.keys()?
Blazemonger
32

Perhatikan bahwa Object.keys dan metode ECMAScript 5 lainnya didukung oleh Firefox 4, Chrome 6, Safari 5, IE 9 dan lebih tinggi.

Sebagai contoh:

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

Tabel kompatibilitas ECMAScript 5: http://kangax.github.com/es5-compat-table/

Deskripsi metode baru: http://markcaudill.com/index.php/2009/04/javascript-new-features-ecma5/

Sam Dutton
sumber
Periksa juga tombol () di konsol untuk Alat Dev Chrome, Firebug, dll.
Sam Dutton
28

Object.getOwnPropertyNames(obj)

Fungsi ini juga menunjukkan properti yang tidak dapat dihitung selain yang ditunjukkan oleh Object.keys(obj).

Di JS, setiap properti memiliki beberapa properti, termasuk boolean enumerable.

Secara umum, properti non-enumerable lebih "internalis" dan lebih jarang digunakan, tetapi kadang-kadang wawasan untuk melihat mereka untuk melihat apa yang sebenarnya terjadi.

Contoh:

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

Perhatikan juga bagaimana:

  • Object.getOwnPropertyNamesdan Object.keys jangan naik rantai prototipe untuk menemukanbase
  • for in tidak

Lebih lanjut tentang rantai prototipe di sini: https://stackoverflow.com/a/23877420/895245

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
sumber
16

Saya penggemar berat fungsi dump.

http://ajaxian.com/archives/javascript-variable-dump-in-coldfusion teks alternatif

Mat
sumber
1
1 karena saya sampai di sini dengan maksud membangun sesuatu yang serupa (walaupun tidak sebagus).
Camilo Martin
1
netgrow.com.au/assets/files/dump/dump.zip tidak ditemukan Bagaimana saya bisa mengunduh dump javascript?
Kiquenet
@Kiquenet setiap kali saya ingin membangun sesuatu seperti ini, saya menerima pemeriksa objek biasa, jika Anda ingin yang dirender dalam HTML ada hal-hal seperti modul npm . Terus terang apa yang membuat saya macet adalah saya menginginkan sesuatu yang lebih baik daripada apa yang ada di gambar itu tetapi tidak pernah berhasil mengonsepnya. Sangat buruk untuk menelusuri objek di inspektur tetapi heuristik untuk mencoba dan menyimpulkan makna dari objek yang berubah-ubah (misalnya, memilah array objek ke dalam tabel dengan kolom) tidak selalu berfungsi dalam praktik.
Camilo Martin
Bagaimana dengan Pretty Print Javascript https://j11y.io/demos/prettyprint/ ?
Kiquenet
13

Bisa melakukannya dengan jQuery sebagai berikut:

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

jika Anda mencoba untuk mendapatkan elemen saja tetapi bukan fungsinya maka kode ini dapat membantu Anda

this.getKeys = function() {

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

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

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

ini adalah bagian dari implementasi HashMap saya dan saya hanya ingin kunci, "ini" adalah objek hashmap yang berisi kunci

Zeacuss
sumber
8

Ini akan berfungsi di sebagian besar browser, bahkan di IE8, dan tidak ada perpustakaan apa pun yang diperlukan. var saya adalah kunci Anda.

var myJSONObject =  {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"}; 
var keys=[];
for (var i in myJSONObject ) { keys.push(i); }
alert(keys);
qwerty_jones
sumber
2
Jawaban Anda sepertinya mirip dengan yang sudah diposting, apa lagi yang ingin ditambahkan?
VKen
7

Di bawah browser yang mendukung js 1.8:

[i for(i in obj)]
Rix Beck
sumber
7

Mozilla memiliki detail implementasi lengkap tentang cara melakukannya di browser yang tidak didukung, jika itu membantu:

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

Anda dapat memasukkannya extensions.jssesuka Anda, tetapi mungkin di beberapa jenis file di bagian atas tumpukan skrip Anda.

Kristofer Sommestad
sumber
Implementasi MDN didasarkan pada Andy E's, yang sudah diberikan sebagai jawaban.
outis
5

Menggunakan Reflect.ownKeys()

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

Object.keys dan Object.getOwnPropertyNames tidak bisa mendapatkan properti yang tidak dapat dihitung . Ini berfungsi bahkan untuk properti yang tidak dapat dihitung .

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

Karena saya menggunakan underscore.js di hampir setiap proyek, saya akan menggunakan keysfungsi:

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

Output dari itu adalah:

['name', 'hello']
schmijos
sumber
Ini adalah pustaka toolset untuk fungsionalitas javascript yang sering digunakan: underscorejs.org
schmijos
4

Membangun jawaban yang diterima.

Jika Objek memiliki properti yang ingin Anda panggil katakan .properties () coba!

var keys = Object.keys(myJSONObject);

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

Solusinya bekerja pada kasing dan lintas browser saya:

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
sumber