Bagaimana cara menampilkan semua metode suatu objek?


249

Saya ingin tahu cara mendaftar semua metode yang tersedia untuk objek seperti misalnya:

 alert(show_all_methods(Math));

Ini harus mencetak:

abs, acos, asin, atan, atan2, ceil, cos, exp, floor, log, max, min, pow, random,round, sin, sqrt, tan, 

Jawaban:


298

Anda bisa menggunakan Object.getOwnPropertyNames()untuk mendapatkan semua properti yang dimiliki oleh suatu objek, apakah dapat dihitung atau tidak. Sebagai contoh:

console.log(Object.getOwnPropertyNames(Math));
//-> ["E", "LN10", "LN2", "LOG2E", "LOG10E", "PI", ...etc ]

Anda dapat menggunakan filter()hanya untuk mendapatkan metode:

console.log(Object.getOwnPropertyNames(Math).filter(function (p) {
    return typeof Math[p] === 'function';
}));
//-> ["random", "abs", "acos", "asin", "atan", "ceil", "cos", "exp", ...etc ]

Di browser ES3 (IE 8 dan lebih rendah), properti objek bawaan tidak dapat dihitung. Objek suka windowdan documenttidak built-in, mereka ditentukan oleh browser dan kemungkinan besar dihitung berdasarkan desain.

Dari ECMA-262 Edition 3 :

Objek Global
Ada objek global unik (15.1), yang dibuat sebelum kontrol memasuki konteks eksekusi. Awalnya objek global memiliki sifat-sifat berikut:

• Objek bawaan seperti Matematika, String, Tanggal, parseInt, dll. Ini memiliki atribut {DontEnum} .
• Properti tambahan yang ditentukan host. Ini mungkin termasuk properti yang nilainya adalah objek global itu sendiri; misalnya, dalam model objek dokumen HTML properti jendela objek global adalah objek global itu sendiri.

Ketika kontrol memasuki konteks eksekusi, dan ketika kode ECMAScript dieksekusi, properti tambahan dapat ditambahkan ke objek global dan properti awal dapat diubah.

Saya harus menunjukkan bahwa ini berarti objek-objek itu bukan properti enumerable dari objek Global. Jika Anda melihat melalui sisa dokumen spesifikasi, Anda akan melihat sebagian besar properti bawaan dan metode objek ini memiliki { DontEnum }atribut yang ditetapkan padanya.


Pembaruan: sesama pengguna SO, CMS, membawa bug IE tentang{ DontEnum } perhatian saya.

Alih-alih memeriksa atribut DontEnum, [Microsoft] JScript akan melewati properti apa pun di objek mana pun di mana ada properti dengan nama yang sama dalam rantai prototipe objek yang memiliki atribut DontEnum.

Singkatnya, waspadalah saat menamai properti objek Anda. Jika ada properti prototipe atau metode bawaan dengan nama yang sama maka IE akan melewatinya saat menggunakan for...inloop.


Andy E, terima kasih telah menunjukkan ini. Jelas saya tidak menyadari hal ini dan saya menghargai upaya Anda untuk menggali ini dan menyebutkannya di sini. Terima kasih lagi :)
Roland Bouman

@Roland: Jangan khawatir. Mungkin agak menyedihkan, tetapi spesifikasi saya sudah tersimpan di folder Dokumen saya, jadi tidak banyak penggalian yang diperlukan kok!
Andy E

Apakah tidak ada cara untuk mendapatkan daftar semua metode dalam implementasi JS yang lebih baru? Suka Node.js dan V8? Bagaimana kita melakukan objek refleksi dan introspeksi seperti yang biasa kita lakukan, seperti untuk kerangka kerja obyek tiruan dll? Saya pikir saya baru saja melupakan JS, tapi saya kira semuanya telah berubah selama bertahun-tahun :)
d11wtq

2
@ d11wtq, dengan implementasi ES5, Anda dapat memanggil Object.getOwnPropertyNames(), yang akan mengembalikan bahkan properti dan metode yang tidak dapat dihitung.
Andy E

karena semua objek mewarisi dari prototipe mereka, bukankah lebih baik melakukan sesuatu seperti Object.getOwnPropertyNames(Array.prototype) ?
lfender6445

71

Ini tidak mungkin dengan ES3 karena properti memiliki DontEnumatribut internal yang mencegah kami menghitung properti ini. ES5, di sisi lain, menyediakan deskriptor properti untuk mengontrol kemampuan enumerasi properti sehingga properti yang ditentukan pengguna dan asli dapat menggunakan antarmuka yang sama dan menikmati kemampuan yang sama, yang mencakup kemampuan untuk melihat properti non-enumerable secara terprogram.

The getOwnPropertyNamesfungsi dapat digunakan untuk menghitung atas semua sifat-sifat berlalu dalam objek, termasuk mereka yang non-enumerable. Kemudian pemeriksaan sederhana typeofdapat digunakan untuk menyaring non-fungsi. Sayangnya, Chrome adalah satu-satunya browser yang berfungsi saat ini.

function getAllMethods(object) {
    return Object.getOwnPropertyNames(object).filter(function(property) {
        return typeof object[property] == 'function';
    });
}

console.log(getAllMethods(Math));

log ["cos", "pow", "log", "tan", "sqrt", "ceil", "asin", "abs", "max", "exp", "atan2", "random", "round", "floor", "acos", "atan", "min", "sin"]tanpa urutan tertentu.


+1 untuk hal-hal ES5. IE9 seharusnya akan sepenuhnya mendukung ES5 sehingga hal ini baik untuk diketahui.
Andy E

1
@Andy - Microsoft memperlakukan IE9 dengan sangat serius yang membuat saya senang :)
Anurag

console.log (function (a) {return Object.getOwnPropertyNames (a) .filter (function (b) {return "function" == typeof a [b]})} (Math)); Terima kasih!
19h

1
getOwnPropertyNames adalah tiketnya. Bahkan bekerja di Nashorn. Mereka baru saja mengubah nama metode objek Java, dan saya bisa mengetahui nama-nama baru dengan menjalankan Object.getOwnPropertyNames (Java)
cayhorstmann

60
var methods = [];
for (var m in obj) {
    if (typeof obj[m] == "function") {
        methods.push(m);
    }
}
alert(methods.join(","));

Dengan cara ini, Anda akan mendapatkan semua metode yang dapat Anda panggil obj. Ini termasuk metode yang "diwariskan" dari prototipe-nya (seperti getMethods()di java). Jika Anda hanya ingin melihat metode-metode yang didefinisikan secara langsung oleh objAnda dapat memeriksa dengan hasOwnProperty:

var methods = [];
for (var m in obj) {        
    if (typeof obj[m] == "function" && obj.hasOwnProperty(m)) {
        methods.push(m);
    }
}
alert(methods.join(","));

ya, aku juga memperhatikan itu. Ketika saya menggunakan sesuatu seperti documentatau windowsaya mendapatkan lebih banyak keberuntungan. Terus terang itu agak tidak terduga, saya tidak tahu mengapa itu tidak berhasil untuk Matematika dll.
Roland Bouman

4
@Roland: Itu karena documentdan windowobjek dengan properti enumerable yang disediakan oleh browser, mereka bukan bagian dari runtime scripting. Objek asli adalah dan jelas properti tidak dapat dihitung.
Andy E

1
Setiap E, saya tidak setuju itu jelas. Maksud saya, itu jelas karena kita sepertinya tidak dapat menyebutkannya. Tapi saya tidak melihat logika mengapa built-in itu harus mencegah penghitungan properti mereka. Hanya ingin tahu, apakah ada beberapa bagian dari standar yang mengatakan built-in ini seharusnya tidak memiliki sifat enumerable?
Roland Bouman

@Roland: maaf, maksudku jelas mereka tidak terhitung karena mereka tidak muncul dengan for-in. Lihat jawaban saya di bawah untuk kutipan dari spec.
Andy E

@Mic: Math adalah objek bawaan yang propertinya tidak dapat dihitung.
Andy E

31

Sebagian besar dukungan browser modern console.dir(obj), yang akan mengembalikan semua properti dari objek yang diwarisi melalui konstruktornya. Lihat dokumentasi Mozilla untuk info lebih lanjut dan dukungan browser saat ini.

console.dir(Math)
=> MathConstructor
E: 2.718281828459045
LN2: 0.6931471805599453
...
tan: function tan() { [native code] }
__proto__: Object

4

Jawaban lain di sini berfungsi untuk sesuatu seperti Matematika, yang merupakan objek statis. Tetapi mereka tidak bekerja untuk instance objek, seperti kencan. Saya menemukan yang berikut ini berfungsi:

function getMethods(o) {
  return Object.getOwnPropertyNames(Object.getPrototypeOf(o))
    .filter(m => 'function' === typeof o[m])
}
//example: getMethods(new Date()):  [ 'getFullYear', 'setMonth', ... ]

https://jsfiddle.net/3xrsead0/

Ini tidak akan berfungsi untuk sesuatu seperti pertanyaan awal (Matematika), jadi pilih solusi Anda berdasarkan kebutuhan Anda. Saya memposting ini di sini karena Google mengirim saya ke pertanyaan ini, tetapi saya ingin tahu bagaimana melakukan ini untuk contoh objek.


3

Jawaban singkatnya adalah Anda tidak bisa karena Mathdan Date(dari atas kepala saya, saya yakin ada orang lain) bukan objek normal. Untuk melihatnya, buat skrip pengujian sederhana:

<html>
  <body>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js"></script>
    <script type="text/javascript">
      $(function() {
        alert("Math: " + Math);
        alert("Math: " + Math.sqrt);
        alert("Date: " + Date);
        alert("Array: " + Array);
        alert("jQuery: " + jQuery);
        alert("Document: " + document);
        alert("Document: " + document.ready);
      });
    </script>
  </body>
</html>

Anda melihatnya menyajikan sebagai objek dengan cara yang sama dengan yang dilakukan dokumen secara keseluruhan, tetapi ketika Anda benar-benar mencoba dan melihat dalam objek itu, Anda melihat bahwa itu adalah kode asli dan sesuatu yang tidak diekspos dengan cara yang sama untuk penghitungan.


1

Mathmemiliki metode statis di mana Anda dapat memanggil langsung suka Math.abs()sementara Datememiliki metode statis suka Date.now()dan juga metode contoh di mana Anda perlu membuat instance baru terlebih dahulu var time = new Date()untuk memanggil time.getHours().

// The instance method of Date can be found on `Date.prototype` so you can just call:
var keys = Object.getOwnPropertyNames(Date.prototype);

// And for the static method
var keys = Object.getOwnPropertyNames(Date);

// But if the instance already created you need to
// pass its constructor
var time = new Date();
var staticKeys = Object.getOwnPropertyNames(time.constructor);
var instanceKeys = Object.getOwnPropertyNames(time.constructor.prototype);

Tentu saja Anda perlu memfilter kunci yang diperoleh untuk metode statis untuk mendapatkan nama metode yang sebenarnya, karena Anda juga bisa mendapatkanlength, name itu bukan fungsi pada daftar.

Tetapi bagaimana jika kita ingin mendapatkan semua metode yang tersedia dari kelas yang memperluas kelas lain?
Tentu saja Anda harus memindai melalui akar prototipe seperti menggunakan __proto__. Untuk menghemat waktu Anda, Anda dapat menggunakan skrip di bawah ini untuk mendapatkan metode statis dan contoh metode mendalam.

// var keys = new Set();
function getStaticMethods(keys, clas){
    var keys2 = Object.getOwnPropertyNames(clas);

    for(var i = 0; i < keys2.length; i++){
        if(clas[keys2[i]].constructor === Function)
            keys.add(keys2[i]);
    }
}

function getPrototypeMethods(keys, clas){
    if(clas.prototype === void 0)
        return;

    var keys2 = Object.getOwnPropertyNames(clas.prototype);
    for (var i = keys2.length - 1; i >= 0; i--) {
        if(keys2[i] !== 'constructor')
            keys.add(keys2[i]);
    }

    var deep = Object.getPrototypeOf(clas);
    if(deep.prototype !== void 0)
        getPrototypeMethods(keys, deep);
}

// ====== Usage example ======
// To avoid duplicate on deeper prototype we use `Set`
var keys = new Set();
getStaticMethods(keys, Date);
getPrototypeMethods(keys, Date);

console.log(Array.from(keys));

Jika Anda ingin mendapatkan metode dari instance yang dibuat, jangan lupa untuk melewatkannya constructor.


0

Saya percaya ada alasan historis sederhana mengapa Anda tidak dapat menyebutkan metode objek bawaan seperti Array misalnya. Inilah alasannya:

Metode adalah properti dari prototipe-objek, misalnya Object.prototype. Itu berarti bahwa semua instance Object akan mewarisi metode-metode itu. Itu sebabnya Anda bisa menggunakan metode itu pada objek apa pun. Katakan .toString () misalnya.

Jadi, JIKA metode dihitung, dan saya akan beralih mengatakan {a: 123} dengan: "for (masukkan {a: 123}) {...}" apa yang akan terjadi? Berapa kali loop itu dieksekusi?

Itu akan diulang sekali untuk satu kunci 'a' dalam contoh kita. TETAPI JUGA satu kali untuk setiap properti enumerable Object.prototype. Jadi jika metode enumerable (secara default), maka setiap loop atas objek apa pun akan mengulang semua metode yang diwarisi.


1
karena primitif biasanya mewarisi dari prototipe, ini dimungkinkan Object.getOwnPropertyNames(Array.prototype)misalnya
lfender6445

apa maksudmu metode adalah properti dari Object.prototype. ? Setiap properti adalah properti Object.prototype jika Object
debugmode
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.