如何显示一个对象的所有方法?

我想知道如何列出一个对象可用的所有方法,例如:

 alert(show_all_methods(Math));

这应该打印:

abs, acos, asin, atan, atan2, ceil, cos, exp, floor, log, max, min, pow, random,round, sin, sqrt, tan, …
274082 次浏览
var methods = [];
for (var m in obj) {
if (typeof obj[m] == "function") {
methods.push(m);
}
}
alert(methods.join(","));

这样,你将得到所有你可以在obj上调用的方法。这包括它从原型中“继承”的方法(如java中的getMethods())。如果你只想查看那些由obj直接定义的方法,你可以使用hasOwnProperty检查:

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

简单的回答是你不能,因为MathDate(在我的脑海中,我相信还有其他的)不是正常的对象。为了看到这一点,创建一个简单的测试脚本:

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

你可以看到它作为一个对象的表现方式和文档的表现方式是一样的,但是当你真正尝试在那个对象中观察时,你会看到它是原生代码而不是以相同的方式为枚举公开的东西。

你可以使用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浏览器(ie8及以下版本)中,内置对象的属性是不可枚举的。像windowdocument这样的对象不是内置的,它们是由浏览器定义的,很可能是设计上可枚举的。

ECMA-262版本3:

< p > 全局对象 < br > 有一个独一无二的全局 对象(15.1),它是前面创建的 控件进入任何执行上下文。 初始全局对象具有 以下属性:

< p >•内置 对象,比如Math, String, Date, 这些属性为{ DontEnum} < /强>。< br > •定义额外的主机 属性。这可能包括 属性,其值为全局变量 对象本身;例如,在 HTML文档对象模型窗口 属性 全局对象本身。< / p > < p >控制 进入执行上下文,和as 执行ECMAScript代码, 可以添加其他属性 全局对象和初始值

.属性可能被改变

我应该指出,这意味着这些对象不是全局对象的可枚举属性。如果你查看规范文档的其余部分,你会看到这些对象的大多数内置属性和方法都设置了{ DontEnum }属性。


更新:一个SO用户CMS让我注意到关于{ DontEnum }的IE错误

而不是检查DontEnum属性,[Microsoft] JScript将跳过任何对象中的任何属性,在对象的原型链中有一个具有DontEnum属性的同名属性。

简而言之,在命名对象属性时要小心。如果存在同名的内置原型属性或方法,则IE在使用for...in循环时将跳过它。

大多数现代浏览器支持console.dir(obj),它将返回通过构造函数继承的对象的所有属性。有关更多信息和当前浏览器支持,请参阅Mozilla的文档

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

这在ES3中是不可能的,因为属性有一个内部DontEnum属性,这阻止了我们枚举这些属性。另一方面,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"]日志没有特定的顺序。

我相信有一个简单的历史原因,为什么你不能列举 使用内置对象的方法,例如Array。原因:< / p > 方法是prototype-object的属性,比如Object.prototype。 这意味着所有object实例都将继承这些方法。这是 为什么你可以在任何对象上使用这些方法。例如:. tostring ()

所以IF方法是可枚举的,我将遍历{a:123} 使用:"for(输入{a:123}){…会发生什么?多少次 循环会被执行吗?< / p > 在我们的例子中,对于单个键'a'它将被迭代一次。但也 Object.prototype的每个可列举的属性一次。因此,如果 方法是可枚举的(默认情况下),那么在任何对象上的任何循环都将循环

这里的其他答案适用于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/

这个不会适用于原始问题(数学),所以根据你的需要选择你的解决方案。我在这里张贴这个,因为谷歌发送给我这个问题,但我想知道如何为对象的实例这样做。

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__一样扫描prototype的根。为了节省你的时间,你可以使用下面的脚本来获得静态方法和深层方法实例。

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

与ES6类和继承很好地工作的方法

这可能是大多数像我这样的ES6新手在寻找“如何列出对象方法”时的意思。

这已改编自:https://stackoverflow.com/a/47714550/895245

// Define getMethods.
const isGetter = (x, name) => (Object.getOwnPropertyDescriptor(x, name) || {}).get
const isFunction = (x, name) => typeof x[name] === "function";
const deepFunctions = x =>
x && x !== Object.prototype &&
Object.getOwnPropertyNames(x)
.filter(name => isGetter(x, name) || isFunction(x, name))
.concat(deepFunctions(Object.getPrototypeOf(x)) || []);
const distinctDeepFunctions = x => Array.from(new Set(deepFunctions(x)));
const getMethods = (obj) => distinctDeepFunctions(obj).filter(
name => name !== "constructor" && !~name.indexOf("__"));


// Example usage.


class BaseClass {
override() { }
baseMethod() { }
}


class DerivedClass extends BaseClass {
override() { }
get myGetter() { }
static myStatic() { }
}


const obj = new DerivedClass();
const methods = getMethods(obj)
methods.sort()
const assert = require('assert')
assert(methods[0] === 'baseMethod')
assert(methods[1] === 'myGetter')
assert(methods[2] === 'override')


console.log(getMethods(Math))

注意它还包括基类的方法,因为大多数用户都想知道他们可以在对象上调用哪些方法。

它似乎也适用于Math,它输出:

[
'abs',    'acos',  'acosh',  'asin',
'asinh',  'atan',  'atanh',  'atan2',
'ceil',   'cbrt',  'expm1',  'clz32',
'cos',    'cosh',  'exp',    'floor',
'fround', 'hypot', 'imul',   'log',
'log1p',  'log2',  'log10',  'max',
'min',    'pow',   'random', 'round',
'sign',   'sin',   'sinh',   'sqrt',
'tan',    'tanh',  'trunc'
]

在Node.js 14.17.0上测试。

如果你想要包括继承方法在内的所有方法:

function getMethods(obj) {
const methods = [];
do {
for (const prop of Object.getOwnPropertyNames(obj)) {
if (obj[prop] instanceof Function) methods.push(prop);
}
obj = Object.getPrototypeOf(obj);
} while (obj !== null)


return methods;
}


console.log(getMethods(Math));

受到其他答案的启发,这里有一种查找所有方法的递归方法:

// Find all methods of an object, up to the root prototype
function findAllMethods(obj, methods = []) {
if (!obj) {
return [...new Set(methods)];
}
  

const props = Object.getOwnPropertyNames(obj);
return findAllMethods(Object.getPrototypeOf(obj), [
...methods,
...props.filter(prop => typeof obj[prop] === 'function'),
]);
}