如何显示一个对象的所有方法?
Posted
技术标签:
【中文标题】如何显示一个对象的所有方法?【英文标题】:How to display all methods of an object? 【发布时间】:2011-01-16 12:16:12 【问题描述】:我想知道如何列出对象的所有可用方法,例如:
alert(show_all_methods(Math));
这应该打印出来:
abs, acos, asin, atan, atan2, ceil, cos, exp, floor, log, max, min, pow, random,round, sin, sqrt, tan, …
【问题讨论】:
【参考方案1】: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(","));
【讨论】:
是的,我也注意到了这一点。当我使用document
或window
之类的东西时,我会得到更多的运气。坦率地说,这有点出乎意料,我不知道为什么它不适用于数学等。
@Roland:这是因为document
和window
是浏览器提供的具有可枚举属性的对象,它们不是脚本运行时的一部分。原生对象显然是不可枚举的。
任何 E,我不同意这是显而易见的。我的意思是,这很明显,因为我们似乎无法列举它们。但是我不明白为什么这些内置函数应该阻止枚举它们的属性的逻辑。只是好奇,标准中是否有部分规定这些内置函数不应具有可枚举的属性?
@Roland:抱歉,我的意思是很明显它们是不可枚举的,因为它们没有出现 for-in。请参阅下面我的回答以获取规范的引用。
@Mic:Math 是一个内置对象,其属性不可枚举。【参考方案2】:
简短的回答是你不能,因为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>
您会看到它以与 document 整体相同的方式呈现为一个对象,但是当您实际尝试查看该对象时,您会发现它是本机代码,并且某些东西以不同的方式公开用于枚举。
【讨论】:
【参考方案3】:您可以使用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
之类的对象不是内置的,它们是由浏览器定义的,很可能是设计可枚举的。
来自ECMA-262 Edition 3:
全局对象 有一个独特的全球 对象(15.1),它是在之前创建的 控制进入任何执行上下文。 最初,全局对象具有 以下属性:
• 内置 对象,例如数学、字符串、日期、 parseInt 等 这些都有属性 DontEnum 。 • 定义了额外的主机 特性。这可能包括一个 值为全局的属性 对象本身;例如,在 HTML 文档对象模型窗口 全局对象的属性是 全局对象本身。
作为控制 进入执行上下文,并且作为 执行 ECMAScript 代码, 可以添加其他属性 全局对象和初始 属性可能会改变。
我应该指出,这意味着这些对象不是 Global 对象的可枚举属性。如果您查看规范文档的其余部分,您会发现这些对象的大部分内置属性和方法都设置了 DontEnum
属性。
更新:一位 SO 用户 CMS 引起了我的注意,IE bug regarding DontEnum
。
[Microsoft] JScript 不检查 DontEnum 属性,而是跳过对象原型链中具有 DontEnum 属性的同名属性的任何对象中的任何属性。
简而言之,在命名对象属性时要小心。如果存在同名的内置原型属性或方法,则 IE 在使用for...in
循环时会跳过它。
【讨论】:
安迪 E,感谢您指出这一点。显然我没有意识到这一点,我感谢您努力挖掘并在这里提及它。再次感谢:) @Roland:不用担心。也许有点难过,但我的文档文件夹中存储了规范,所以真的不需要太多挖掘! 那么,有没有办法在较新的 JS 实现中获取所有方法的列表呢?喜欢 Node.js 和 V8?我们如何像以前一样进行反射和内省对象,例如模拟对象框架等?我以为我只是忘记了 JS,但我想这些年来事情已经发生了变化 :) @d11wtq,使用 ES5 实现,您可以调用Object.getOwnPropertyNames()
,它甚至会返回不可枚举的属性和方法。
既然所有对象都继承自它们的原型,那么做Object.getOwnPropertyNames(Array.prototype)
之类的东西不是更好吗?【参考方案4】:
大多数现代浏览器都支持console.dir(obj)
,它将返回通过其构造函数继承的对象的所有属性。有关更多信息和当前浏览器支持,请参阅 Mozilla 的 documentation。
console.dir(Math)
=> MathConstructor
E: 2.718281828459045
LN2: 0.6931471805599453
...
tan: function tan() [native code]
__proto__: Object
【讨论】:
【参考方案5】:这在 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"]
。
【讨论】:
+1 用于 ES5 的东西。据说 IE9 将完全支持 ES5,所以很高兴知道这一点。 @Andy - 微软非常重视 IE9,这让我很高兴 :) console.log(function(a)return Object.getOwnPropertyNames(a).filter(function(b)return"function"==typeof a[b])(数学)) ;谢谢! getOwnPropertyNames 是票。它甚至适用于 Nashorn。他们只是更改了 Java 对象的方法名称,我能够通过运行 Object.getOwnPropertyNames(Java) 找出新名称【参考方案6】:我相信你不能列举一个简单的历史原因 例如 Array 等内置对象的方法。原因如下:
方法是原型对象的属性,比如 Object.prototype。 这意味着所有对象实例都将继承这些方法。那是 为什么你可以在任何对象上使用这些方法。例如说 .toString()。
所以 IF 方法是可枚举的,我会重复说 a:123 with: "for (key in a:123) ..." 会发生什么?多少次 会执行那个循环吗?
在我们的示例中,它将为单个键“a”迭代一次。但是也 Object.prototype 的每个 enumerable 属性一次。因此,如果 方法是可枚举的(默认情况下),然后任何对象上的任何循环都会循环 也包括所有继承的方法。
【讨论】:
因为原语通常从原型继承,这可能是Object.getOwnPropertyNames(Array.prototype)
例如
你的意思是方法是 Object.prototype 的属性。 ?在 Object 的情况下,每个属性都是 Object.prototype 的属性【参考方案7】:
这里的其他答案适用于数学之类的东西,它是一个静态对象。但它们不适用于对象的实例,例如日期。我发现以下工作:
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 向我发送了此问题,但我想知道如何为对象实例执行此操作。
【讨论】:
【参考方案8】: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
。 p>
但是如果我们想从扩展另一个类的类中获取所有可用的方法呢?
当然,您需要像使用__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
。
【讨论】:
【参考方案9】:适用于 ES6 类和继承的方法
这可能是大多数像我这样的新手 ES6 用户在寻找“如何列出对象方法”时的意思。
改编自:https://***.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 上测试。
【讨论】:
非常感谢。出于兴趣,怎么了:!~name ? @user48956 我不知道,但wsvincent.com/javascript-tilde 解释说,它是二进制否定并将-1 转换为0。 是的——但是使用二进制否定有点不寻常,除非你正在处理数字的位操作(对于所有其他情况,通常使用布尔否定:!) 或者换一种说法,为什么不是-1!==name.indexOf(""),或者-1===name.indexOf("") @user48956 性能适合初学者,真正的专业人士只关心code golfing以上是关于如何显示一个对象的所有方法?的主要内容,如果未能解决你的问题,请参考以下文章
如何查找场景中所有的物体啊,包括在Hierarchy中不显示的物体