オブジェクトのすべてのメソッドを表示する方法は?


249

たとえば、オブジェクトで使用できるすべてのメソッドを一覧表示する方法を知りたいです。

 alert(show_all_methods(Math));

これは印刷する必要があります:

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

回答:


298

を使用Object.getOwnPropertyNames()して、列挙可能かどうかにかかわらず、オブジェクトに属するすべてのプロパティを取得できます。例えば:

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

次に、を使用filter()してメソッドのみを取得できます。

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

ES3ブラウザー(IE 8以下)では、組み込みオブジェクトのプロパティは列挙できません。以下のようなオブジェクトwindowとはdocument、内蔵されていない彼らは、ブラウザやデザインである可能性が最も高くEnumerableによって定義されています、。

ECMA-262第3版

グローバルオブジェクト
一意のグローバルオブジェクト(15.1)があり、コントロールが実行コンテキストに入る前に作成されます。最初、グローバルオブジェクトには次のプロパティがあります。

•Math、String、Date、parseIntなどの組み込みオブジェクト。これらの属性は{DontEnum}です。
•追加のホスト定義プロパティ。これには、値がグローバルオブジェクト自体であるプロパティが含まれる場合があります。たとえば、HTMLドキュメントオブジェクトモデルでは、グローバルオブジェクトのウィンドウプロパティはグローバルオブジェクト自体です。

コントロールが実行コンテキストに入り、ECMAScriptコードが実行されると、追加のプロパティがグローバルオブジェクトに追加され、初期プロパティが変更される場合があります。

これは、これらのオブジェクトがグローバルオブジェクトの列挙可能なプロパティではないことを意味することを指摘しておきます。仕様ドキュメントの残りの部分を見ると、これらのオブジェクトの組み込みプロパティとメソッドのほとんどに{ DontEnum }属性が設定されていることがわかります。


更新:SOユーザーの仲間であるCMSが、私の注意に関してIEバグを{ DontEnum }もたらしました。

[Microsoft] JScriptは、DontEnum属性をチェックする代わりに、DontEnum属性を持つオブジェクトのプロトタイプチェーンに同じ名前のプロパティがあるオブジェクトのプロパティをスキップします。

つまり、オブジェクトのプロパティに名前を付けるときは注意してください。同じ名前の組み込みプロトタイププロパティまたはメソッドがある場合、IEはfor...inループを使用するときにそれらをスキップします。


アンディE、これを指摘してくれてありがとう。明らかに私はこれに気づいていなかったので、これを掘り下げてここで言及する努力に感謝します。ありがとうございました:)
Roland Bouman、2010

@ローランド:心配する必要はありません。少し悲しいかもしれませんが、仕様はドキュメントフォルダーに保存されているので、実際に掘る必要はあまりありません。
アンディE

それでは、新しいJS実装のすべてのメソッドのリストを取得する方法はありませんか?Node.jsやV8は好きですか?モックオブジェクトフレームワークなど、以前と同じようにオブジェクトをリフレクションおよびイントロスペクトするにはどうすればよいですか?私はJSを忘れただけだと思っていましたが、年月の経過とともに状況は変化したと思います:)
d11wtq '19

2
@ d11wtqは、ES5実装でを呼び出すことができますObject.getOwnPropertyNames()。これにより、列挙できないプロパティとメソッドも返されます。
アンディE

すべてのオブジェクトはプロトタイプから継承するので、次のようなことをした方がいいのではない Object.getOwnPropertyNames(Array.prototype) ですか
lfender6445 2016

71

プロパティには内部DontEnum属性があり、これらのプロパティを列挙できないため、ES3では不可能です。一方、ES5は、プロパティの列挙機能を制御するためのプロパティ記述子を提供します。これにより、ユーザー定義プロパティとネイティブプロパティが同じインターフェイスを使用し、同じ機能を楽しむことができます。

このgetOwnPropertyNames関数を使用して、列挙できないものも含め、渡されたオブジェクトのすべてのプロパティを列挙できます。次に、単純なtypeofチェックを使用して、非関数を除外できます。残念ながら、Chromeは現在動作している唯一のブラウザーです。

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

console.log(getAllMethods(Math));

["cos", "pow", "log", "tan", "sqrt", "ceil", "asin", "abs", "max", "exp", "atan2", "random", "round", "floor", "acos", "atan", "min", "sin"]順不同でログを記録します。


ES5の+1。IE9はおそらくES5を完全にサポートするので、このことは知っておくと良いでしょう。
Andy E

1
@Andy-MicrosoftはIE9を非常に真剣に受け止めており、私を幸せにしています:)
Anurag

console.log(function(a){return Object.getOwnPropertyNames(a).filter(function(b){return "function" == typeof a [b]})}(Math)); ありがとうございました!
19h

1
getOwnPropertyNamesはチケットです。Nashornでも機能します。彼らはJavaオブジェクトのメソッドの名前を変更しただけで、Object.getOwnPropertyNames(Java)を実行して新しい名前を理解することができました
cayhorstmann

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

このようにして、呼び出すことができるすべてのメソッドを取得しますobj。これには、プロトタイプから「継承」するメソッド(getMethods()Javaなど)が含まれます。直接定義されたメソッドだけを見たい場合は、obj次のコマンドで確認できますhasOwnProperty

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

ええ、私も気づいています。私は何かのようなものを使うとき、documentまたはwindow私はより多くの運を得ます。率直に言って、それは少し予想外で、私はそれが数学などのために動作しない理由がわからない
ローランドBouman

4
@Roland:ので、それはだdocumentwindowブラウザが提供する列挙プロパティを持つオブジェクトである、彼らはスクリプトランタイムの一部ではないです。ネイティブオブジェクトはもちろん、プロパティは列挙可能ではありません。
アンディE

1
任意のE、私はそれが明白であることに同意しません。つまり、それらを列挙することができないため、明らかです。しかし、なぜそれらの組み込み関数がプロパティの列挙を妨げるべきなのかについての論理はわかりません。気になるのは、これらの組み込み関数に列挙可能なプロパティがあってはならないという標準の一部はありますか?
Roland Bouman、2010

@ローランド:申し訳ありませんが、for-inが表示されないため、列挙できないことは明らかです。仕様からの引用については、以下の私の回答を参照してください。
アンディE

@Mic:Mathは組み込みオブジェクトであり、そのプロパティは列挙できません。
アンディE

31

最新のブラウザーサポートはconsole.dir(obj)、コンストラクターを介して継承したオブジェクトのすべてのプロパティを返します。詳細と現在のブラウザのサポートについては、Mozillaのドキュメントを参照してください。

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

4

ここでの他の答えは、静的オブジェクトであるMathのようなもので機能します。ただし、日付などのオブジェクトのインスタンスでは機能しません。以下が機能することがわかりました:

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/

これ元の質問(数学)のようなものに機能しないため、ニーズに基づいてソリューションを選択してください。Googleからこの質問に送られたので、ここに投稿しましたが、オブジェクトのインスタンスに対してこれを行う方法を知りたいと思っていました。


3

簡単な答えは、あなたはできません。MathそしてDate(そして頭の上から、確かに他にもあると思います)は通常のオブジェクトではありません。これを確認するには、簡単なテストスクリプトを作成します。

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

ドキュメント全体と同じ方法でオブジェクトとして表示されますが、実際にそのオブジェクトを試してみると、ネイティブコードであり、列挙と同じ方法で公開されていないことがわかります。


1

Mathあなたのような直接呼び出すことができる静的メソッドがあるMath.abs()一方でDate、静的などの方法があるDate.now()あなたが最初の新しいインスタンスを作成する必要があり、また、インスタンスメソッドvar time = new Date()の呼び出しには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);

もちろん、実際のメソッド名を取得するには、静的メソッドの取得されたキーをフィルタリングする必要がありますlength, name。これは、リストにある関数ではないものを取得することもできるためです。

しかし、別のクラスを拡張するクラスからすべての利用可能なメソッドを取得したい場合はどうでしょうか?
もちろん、のようにプロトタイプのルートをスキャンする必要があります__proto__。時間を節約するために、以下のスクリプトを使用して静的メソッドとディープメソッドインスタンスを取得できます。

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

作成したインスタンスからメソッドを取得したい場合はconstructor、それを渡すことを忘れないでください。


0

Arrayなどの組み込みオブジェクトのメソッドを列挙できない単純な歴史的理由があると思います。理由は次のとおりです。

メソッドは、プロトタイプオブジェクトのプロパティです(Object.prototypeなど)。つまり、すべてのオブジェクトインスタンスはこれらのメソッドを継承します。これが、これらのメソッドを任意のオブジェクトで使用できる理由です。たとえば.toString()と言います。

したがって、IFメソッドは列挙可能であり、「for(key in {a:123}){...}」を使用して{a:123}を繰り返し処理するとどうなりますか?そのループは何回実行されますか?

この例では、単一のキー「a」に対して1回繰り返されます。ただし、Object.prototypeの列挙可能なプロパティごとに1回。したがって、メソッドが(デフォルトで)列挙可能である場合、オブジェクトをループすると、継承されたすべてのメソッドもループします。


1
プリミティブは通常プロトタイプから継承するため、これはObject.getOwnPropertyNames(Array.prototype)たとえば可能です
lfender6445

メソッドはObject.prototypeのプロパティです。?オブジェクトの場合、すべてのプロパティはObject.prototypeのプロパティです
debugmode
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.