我想知道如何列出对象可用的所有方法,例如:
alert(show_all_methods(Math));
这应该打印:
abs, acos, asin, atan, atan2, ceil, cos, exp, floor, log, max, min, pow, random,round, sin, sqrt, tan, …
答案 0 :(得分:266)
您可以使用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
这样的对象不是内置的,它们是由浏览器定义的,很可能是设计可枚举的。
全球对象
有一个独特的全球性 对象(15.1),之前创建的 控制进入任何执行上下文。 最初全局对象有 以下属性:•内置 数学,字符串,日期等对象 parseInt等这些属性{ DontEnum} 。
•定义了其他主机 属性。这可能包括一个 价值为全球的财产 对象本身;例如,在 HTML文档对象模型窗口 全局对象的属性是 全球对象本身。作为控制 进入执行上下文,并作为 ECMAScript代码被执行, 可以添加其他属性 全局对象和初始对象 属性可能会改变。
我应该指出,这意味着这些对象不是Global对象的可枚举属性。如果查看规范文档的其余部分,您将看到这些对象的大多数内置属性和方法都设置了{ DontEnum }
属性。
更新:一位SO用户,CMS,引起了我IE bug regarding { DontEnum }
的注意。
[Microsoft] JScript不会检查DontEnum属性,而是跳过对象原型链中具有属性DontEnum的同名属性的任何对象中的任何属性。
简而言之,在命名对象属性时要小心。如果存在具有相同名称的内置原型属性或方法,则IE将在使用for...in
循环时跳过它。
答案 1 :(得分:70)
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"]
。
答案 2 :(得分:54)
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(","));
答案 3 :(得分:27)
大多数现代浏览器支持console.dir(obj)
,它将返回通过其构造函数继承的对象的所有属性。有关更多信息和当前浏览器支持,请参阅Mozilla的documentation。
console.dir(Math)
=> MathConstructor
E: 2.718281828459045
LN2: 0.6931471805599453
...
tan: function tan() { [native code] }
__proto__: Object
答案 4 :(得分: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>
你看到它作为一个对象呈现与文档整体相同的方式,但当你真正尝试在该对象中看到它时,你会看到它是本机代码,并且没有以相同的方式暴露枚举。
答案 5 :(得分:1)
这里的其他答案适用于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向我提出了这个问题,但是我想知道如何针对对象实例执行此操作。
答案 6 :(得分:1)
Math
具有静态方法,您可以像Math.abs()
那样直接调用,而Date
具有静态方法,例如Date.now()
,还有需要首先创建新实例的实例方法{ {1}}呼叫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));
。
答案 7 :(得分:1)
适用于 ES6 类和继承的方法
这可能是大多数像我一样的 ES6 新手在寻找“如何列出对象方法”时的意思。
改编自:https://stackoverflow.com/a/47714550/895245
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 上测试。
答案 8 :(得分:0)
我相信有一个简单的历史原因,你无法枚举 例如,像Array这样的内置对象的方法。原因如下:
方法是prototype-object的属性,比如Object.prototype。 这意味着所有Object-instance都将继承这些方法。那是 为什么你可以在任何对象上使用这些方法。比如说.toString()。
所以IF方法是可枚举的,我会迭代说{a:123} with:“for(key in {a:123}){...}”会发生什么?多少次 会循环执行吗?
对于我们示例中的单个键'a',它将被迭代一次。但是也 对于Object.prototype的每个可枚举属性。因此,如果 方法是可枚举的(默认情况下),然后任何对象上的任何循环都会循环 在其所有继承的方法上也是如此。