Wie werden alle Methoden eines Objekts angezeigt?

249

Ich möchte wissen, wie alle für ein Objekt verfügbaren Methoden aufgelistet werden, wie zum Beispiel:

 alert(show_all_methods(Math));

Dies sollte drucken:

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

Antworten:

298

Mit können Object.getOwnPropertyNames()Sie alle Eigenschaften abrufen, die zu einem Objekt gehören, unabhängig davon, ob sie aufzählbar sind oder nicht. Beispielsweise:

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

Sie können dann filter()nur die folgenden Methoden verwenden:

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

In ES3-Browsern (IE 8 und niedriger) sind die Eigenschaften von integrierten Objekten nicht aufzählbar. Objekte mögen windowund documentsind nicht eingebaut, sie werden vom Browser definiert und sind höchstwahrscheinlich vom Design her aufzählbar.

Aus ECMA-262 Edition 3 :

Globales Objekt
Es gibt ein eindeutiges globales Objekt (15.1), das erstellt wird, bevor das Steuerelement in einen Ausführungskontext eintritt. Zu Beginn hat das globale Objekt die folgenden Eigenschaften:

• Integrierte Objekte wie Math, String, Date, parseInt usw. Diese haben Attribute {DontEnum} .
• Zusätzliche vom Host definierte Eigenschaften. Dies kann eine Eigenschaft umfassen, deren Wert das globale Objekt selbst ist. Im HTML-Dokumentobjektmodell ist die Fenstereigenschaft des globalen Objekts beispielsweise das globale Objekt selbst.

Wenn die Steuerung in Ausführungskontexte eintritt und ECMAScript-Code ausgeführt wird, können dem globalen Objekt zusätzliche Eigenschaften hinzugefügt und die anfänglichen Eigenschaften geändert werden.

Ich sollte darauf hinweisen, dass dies bedeutet, dass diese Objekte keine aufzählbaren Eigenschaften des globalen Objekts sind. Wenn Sie den Rest des Spezifikationsdokuments durchsehen, werden Sie feststellen, dass für die meisten integrierten Eigenschaften und Methoden dieser Objekte das { DontEnum }Attribut festgelegt ist.


Update: Ein anderer SO-Benutzer, CMS, hat mich auf einen IE-Fehler{ DontEnum } aufmerksam gemacht.

Anstatt das DontEnum-Attribut zu überprüfen, überspringt [Microsoft] JScript jede Eigenschaft in einem Objekt, in der sich in der Prototypkette des Objekts eine gleichnamige Eigenschaft mit dem Attribut DontEnum befindet.

Kurz gesagt, seien Sie vorsichtig, wenn Sie Ihre Objekteigenschaften benennen. Wenn eine integrierte Prototyp-Eigenschaft oder -Methode mit demselben Namen vorhanden ist, überspringt der IE diese, wenn eine for...inSchleife verwendet wird.

Andy E.
quelle
Andy E, danke, dass Sie darauf hingewiesen haben. Ich war mir dessen offensichtlich nicht bewusst und ich schätze Ihre Bemühungen, dies herauszufinden und hier zu erwähnen.
Nochmals
@ Roland: Keine Sorge. Vielleicht ist es ein bisschen traurig, aber ich habe die Spezifikation in meinem Dokumentenordner gespeichert, so dass nicht wirklich viel Graben erforderlich ist!
Andy E
Gibt es dann keine Möglichkeit, eine Liste aller Methoden in neueren JS-Implementierungen abzurufen? Wie Node.js und V8? Wie machen wir Reflexions- und Introspektionsobjekte wie früher, z. B. für Scheinobjekt-Frameworks usw.? Ich dachte, ich hätte JS gerade vergessen, aber ich denke, die Dinge haben sich im Laufe der Jahre geändert :)
d11wtq
2
@ d11wtq, mit ES5-Implementierungen können Sie aufrufen Object.getOwnPropertyNames(), wodurch auch nicht aufzählbare Eigenschaften und Methoden zurückgegeben werden.
Andy E
Da alle Objekte von ihrem Prototyp erben, wäre es nicht besser, so etwas zu tun Object.getOwnPropertyNames(Array.prototype) ?
lfender6445
71

Mit ES3 ist dies nicht möglich, da die Eigenschaften ein internes DontEnumAttribut haben, das uns daran hindert, diese Eigenschaften aufzulisten. ES5 bietet andererseits Eigenschaftsbeschreibungen zum Steuern der Aufzählungsfunktionen von Eigenschaften, sodass benutzerdefinierte und native Eigenschaften dieselbe Schnittstelle verwenden und dieselben Funktionen nutzen können, einschließlich der Möglichkeit, nicht aufzählbare Eigenschaften programmgesteuert anzuzeigen.

Die getOwnPropertyNamesFunktion kann verwendet werden, um alle Eigenschaften des übergebenen Objekts aufzulisten, einschließlich derjenigen, die nicht aufzählbar sind. Dann kann eine einfache typeofPrüfung verwendet werden, um Nichtfunktionen herauszufiltern. Leider ist Chrome der einzige Browser, in dem es derzeit funktioniert.

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

console.log(getAllMethods(Math));

meldet sich ["cos", "pow", "log", "tan", "sqrt", "ceil", "asin", "abs", "max", "exp", "atan2", "random", "round", "floor", "acos", "atan", "min", "sin"]in keiner bestimmten Reihenfolge an.

Anurag
quelle
+1 für das ES5-Zeug. IE9 wird angeblich ES5 vollständig unterstützen, daher ist dieses Zeug gut zu wissen.
Andy E
1
@ Andy - Microsoft nimmt IE9 sehr ernst, was mich glücklich macht :)
Anurag
console.log (Funktion (a) {return Object.getOwnPropertyNames (a) .filter (Funktion (b) {return "function" == Typ eines [b]})} (Math)); Danke dir!
19h
1
getOwnPropertyNames ist das Ticket. Es funktioniert sogar in Nashorn. Sie haben gerade die Namen der Methoden des Java-Objekts geändert, und ich konnte die neuen Namen herausfinden, indem ich Object.getOwnPropertyNames (Java)
cayhorstmann
60
var methods = [];
for (var m in obj) {
    if (typeof obj[m] == "function") {
        methods.push(m);
    }
}
alert(methods.join(","));

Auf diese Weise erhalten Sie alle Methoden, die Sie aufrufen können obj. Dies schließt die Methoden ein, die es von seinem Prototyp "erbt" (wie getMethods()in Java). Wenn Sie nur die direkt von objIhnen definierten Methoden sehen möchten, können Sie Folgendes überprüfen hasOwnProperty:

var methods = [];
for (var m in obj) {        
    if (typeof obj[m] == "function" && obj.hasOwnProperty(m)) {
        methods.push(m);
    }
}
alert(methods.join(","));
Roland Bouman
quelle
Ja, das merke ich auch nur. Wenn ich etwas wie benutze documentoder windowmehr Glück bekomme. Ehrlich gesagt ist es ein bisschen unerwartet, ich weiß nicht, warum es nicht für Mathe usw. funktioniert
Roland Bouman
4
@Roland: Es ist , weil documentund windowsind Objekte mit enumerable Eigenschaften durch den Browser zur Verfügung gestellt, sie sind nicht Teil der Skriptlaufzeit. Native Objekte sind und offensichtlich sind die Eigenschaften nicht aufzählbar.
Andy E
1
Jedes E, ich stimme nicht zu, dass es offensichtlich ist. Ich meine, es ist offensichtlich, da wir sie scheinbar nicht aufzählen können. Ich sehe jedoch keine Logik dafür, warum diese integrierten Funktionen die Aufzählung ihrer Eigenschaften verhindern sollten. Nur neugierig, gibt es einen Teil des Standards, der besagt, dass diese Einbauten keine aufzählbaren Eigenschaften haben sollten?
Roland Bouman
@ Roland: Entschuldigung, ich meinte, dass es offensichtlich ist, dass sie nicht aufzählbar sind, da sie nicht mit einem For-In auftauchen. In meiner Antwort unten finden Sie ein Zitat aus der Spezifikation.
Andy E
@Mic: Math ist ein integriertes Objekt, dessen Eigenschaften nicht aufzählbar sind.
Andy E
31

Modernste Browserunterstützung console.dir(obj), die alle Eigenschaften eines Objekts zurückgibt, das es über seinen Konstruktor geerbt hat. Weitere Informationen und aktuelle Browserunterstützung finden Sie in der Dokumentation von Mozilla .

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

Die anderen Antworten hier funktionieren für etwas wie Mathematik, das ein statisches Objekt ist. Sie funktionieren jedoch nicht für eine Instanz eines Objekts, z. B. ein Datum. Ich fand Folgendes zu funktionieren:

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/

Dies funktioniert nicht für so etwas wie die ursprüngliche Frage (Mathematik). Wählen Sie also Ihre Lösung entsprechend Ihren Anforderungen aus. Ich poste dies hier, weil Google mich zu dieser Frage geschickt hat, aber ich wollte wissen, wie dies für Instanzen von Objekten gemacht wird.

Pennen
quelle
3

Die kurze Antwort lautet: Sie können nicht, weil Mathund Date(ich bin mir sicher, dass es noch andere gibt) keine normalen Objekte sind. Erstellen Sie dazu ein einfaches Testskript:

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

Sie sehen, dass es als Objekt dargestellt wird, wie es das Dokument insgesamt tut, aber wenn Sie tatsächlich versuchen, es in diesem Objekt zu sehen, sehen Sie, dass es sich um nativen Code handelt und etwas, das für die Aufzählung nicht auf die gleiche Weise verfügbar gemacht wird.

Nick Craver
quelle
1

Mathhat eine statische Methode, mit der Sie direkt wie aufrufen können, Math.abs()während Dateeine statische Methode wie Date.now()und eine Instanzmethode, bei der Sie zuerst eine neue Instanz erstellen müssen, um var time = new Date()sie aufzurufen 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);

Natürlich müssen Sie die erhaltenen Schlüssel für die statische Methode filtern , um die tatsächlichen Methodennamen zu erhalten, da Sie auch feststellen können, length, namedass dies keine Funktion in der Liste ist.

Aber wie wäre es, wenn wir alle verfügbaren Methoden von Klassen erhalten möchten, die eine andere Klasse erweitern?
Natürlich müssen Sie die Wurzel des Prototyps wie bei der Verwendung durchsuchen __proto__. Um Zeit zu sparen, können Sie das folgende Skript verwenden, um statische Methoden und Deep-Method-Instanzen abzurufen.

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

Wenn Sie Methoden von einer erstellten Instanz erhalten möchten, vergessen Sie nicht, diese zu übergeben constructor.

StefansArya
quelle
0

Ich glaube, es gibt einen einfachen historischen Grund, warum Sie nicht über Methoden von eingebauten Objekten wie beispielsweise Array aufzählen können. Hier ist der Grund:

Methoden sind Eigenschaften des Prototypobjekts, z. B. Object.prototype. Das bedeutet, dass alle Objektinstanzen diese Methoden erben. Deshalb können Sie diese Methoden für jedes Objekt verwenden. Sagen Sie zum Beispiel .toString ().

WENN Methoden also aufzählbar wären und ich würde sagen, {a: 123} mit: "for ({a: 123} eingeben) {...}" was würde passieren? Wie oft würde diese Schleife ausgeführt?

In unserem Beispiel wird es einmal für den einzelnen Schlüssel 'a' wiederholt. ABER AUCH einmal für jede aufzählbare Eigenschaft von Object.prototype. Wenn also Methoden (standardmäßig) aufzählbar wären, würde jede Schleife über ein Objekt auch alle geerbten Methoden durchlaufen.

Panu Logic
quelle
1
Da Grundelemente normalerweise von einem Prototyp erben, ist dies Object.getOwnPropertyNames(Array.prototype)beispielsweise möglich
lfender6445
Was meinst du Methoden sind Eigenschaften von Object.prototype. ? Jede Eigenschaft ist Eigenschaften von Object.prototype im Fall von Object
Debugmode