回答:
を使用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によって定義されています、。
グローバルオブジェクト
一意のグローバルオブジェクト(15.1)があり、コントロールが実行コンテキストに入る前に作成されます。最初、グローバルオブジェクトには次のプロパティがあります。•Math、String、Date、parseIntなどの組み込みオブジェクト。これらの属性は{DontEnum}です。
•追加のホスト定義プロパティ。これには、値がグローバルオブジェクト自体であるプロパティが含まれる場合があります。たとえば、HTMLドキュメントオブジェクトモデルでは、グローバルオブジェクトのウィンドウプロパティはグローバルオブジェクト自体です。コントロールが実行コンテキストに入り、ECMAScriptコードが実行されると、追加のプロパティがグローバルオブジェクトに追加され、初期プロパティが変更される場合があります。
これは、これらのオブジェクトがグローバルオブジェクトの列挙可能なプロパティではないことを意味することを指摘しておきます。仕様ドキュメントの残りの部分を見ると、これらのオブジェクトの組み込みプロパティとメソッドのほとんどに{ DontEnum }
属性が設定されていることがわかります。
更新:SOユーザーの仲間であるCMSが、私の注意に関してIEバグを{ DontEnum }
もたらしました。
[Microsoft] JScriptは、DontEnum属性をチェックする代わりに、DontEnum属性を持つオブジェクトのプロトタイプチェーンに同じ名前のプロパティがあるオブジェクトのプロパティをスキップします。
つまり、オブジェクトのプロパティに名前を付けるときは注意してください。同じ名前の組み込みプロトタイププロパティまたはメソッドがある場合、IEはfor...in
ループを使用するときにそれらをスキップします。
Object.getOwnPropertyNames()
。これにより、列挙できないプロパティとメソッドも返されます。
Object.getOwnPropertyNames(Array.prototype)
ですか
プロパティには内部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"]
順不同でログを記録します。
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
私はより多くの運を得ます。率直に言って、それは少し予想外で、私はそれが数学などのために動作しない理由がわからない
document
とwindow
ブラウザが提供する列挙プロパティを持つオブジェクトである、彼らはスクリプトランタイムの一部ではないです。ネイティブオブジェクトはもちろん、プロパティは列挙可能ではありません。
ここでの他の答えは、静的オブジェクトである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からこの質問に送られたので、ここに投稿しましたが、オブジェクトのインスタンスに対してこれを行う方法を知りたいと思っていました。
簡単な答えは、あなたはできません。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>
ドキュメント全体と同じ方法でオブジェクトとして表示されますが、実際にそのオブジェクトを試してみると、ネイティブコードであり、列挙と同じ方法で公開されていないことがわかります。
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
、それを渡すことを忘れないでください。
Arrayなどの組み込みオブジェクトのメソッドを列挙できない単純な歴史的理由があると思います。理由は次のとおりです。
メソッドは、プロトタイプオブジェクトのプロパティです(Object.prototypeなど)。つまり、すべてのオブジェクトインスタンスはこれらのメソッドを継承します。これが、これらのメソッドを任意のオブジェクトで使用できる理由です。たとえば.toString()と言います。
したがって、IFメソッドは列挙可能であり、「for(key in {a:123}){...}」を使用して{a:123}を繰り返し処理するとどうなりますか?そのループは何回実行されますか?
この例では、単一のキー「a」に対して1回繰り返されます。ただし、Object.prototypeの列挙可能なプロパティごとに1回。したがって、メソッドが(デフォルトで)列挙可能である場合、オブジェクトをループすると、継承されたすべてのメソッドもループします。
Object.getOwnPropertyNames(Array.prototype)
たとえば可能です