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

 alert(show_all_methods(Math));

这应该打印:

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

当前回答

您可以使用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及以下版本)中,内置对象的属性是不可枚举的。像window和document这样的对象不是内置的,它们是由浏览器定义的,而且很可能是通过设计来枚举的。

来自ECMA-262版3:

Global Object There is a unique global object (15.1), which is created before control enters any execution context. Initially the global object has the following properties: • Built-in objects such as Math, String, Date, parseInt, etc. These have attributes { DontEnum }. • Additional host defined properties. This may include a property whose value is the global object itself; for example, in the HTML document object model the window property of the global object is the global object itself. As control enters execution contexts, and as ECMAScript code is executed, additional properties may be added to the global object and the initial properties may be changed.

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


更新:一个SO用户,CMS,给我带来了一个关于{DontEnum}的IE bug。

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

简而言之,在命名对象属性时要小心。如果有一个内置的原型属性或方法具有相同的名称,那么IE将在使用for…在循环。

其他回答

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(","));

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

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

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

我相信有一个简单的历史原因,为什么你不能列举 使用内置对象的方法,例如Array。原因如下:

方法是prototype-object的属性,比如Object.prototype。 这意味着所有object实例都将继承这些方法。这是 为什么你可以在任何对象上使用这些方法。例如,使用. tostring()。

所以IF方法是可枚举的,我将遍历{a:123} 使用:"for(输入{a:123}){…会发生什么?多少次 循环会被执行吗?

在我们的例子中,对于单个键“a”,它将被迭代一次。但也 Object.prototype的每个可枚举属性一次。因此,如果 方法是可枚举的(默认情况下),那么在任何对象上的任何循环都将循环 对所有继承的方法也是如此。

您可以使用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及以下版本)中,内置对象的属性是不可枚举的。像window和document这样的对象不是内置的,它们是由浏览器定义的,而且很可能是通过设计来枚举的。

来自ECMA-262版3:

Global Object There is a unique global object (15.1), which is created before control enters any execution context. Initially the global object has the following properties: • Built-in objects such as Math, String, Date, parseInt, etc. These have attributes { DontEnum }. • Additional host defined properties. This may include a property whose value is the global object itself; for example, in the HTML document object model the window property of the global object is the global object itself. As control enters execution contexts, and as ECMAScript code is executed, additional properties may be added to the global object and the initial properties may be changed.

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


更新:一个SO用户,CMS,给我带来了一个关于{DontEnum}的IE bug。

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

简而言之,在命名对象属性时要小心。如果有一个内置的原型属性或方法具有相同的名称,那么IE将在使用for…在循环。

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

当然,您将需要过滤静态方法获得的键,以获得实际的方法名称,因为您还可以获得列表中不是函数的长度和名称。

但是,如果我们想从扩展另一个类的类中获得所有可用的方法,该怎么办呢? 当然,你需要像使用__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));

如果你想从创建的实例中获取方法,不要忘记传递它的构造函数。