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

时间:2010-02-13 15:12:07

标签: javascript object methods

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

 alert(show_all_methods(Math));

这应该打印:

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

9 个答案:

答案 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及更低版本)中,内置对象的属性不可枚举。像windowdocument这样的对象不是内置的,它们是由浏览器定义的,很可能是设计可枚举的。

来自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循环时跳过它。

答案 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)

简短的回答是你不能,因为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>

你看到它作为一个对象呈现与文档整体相同的方式,但当你真正尝试在该对象中看到它时,你会看到它是本机代码,并且没有以相同的方式暴露枚举。

答案 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的每个可枚举属性。因此,如果 方法是可枚举的(默认情况下),然后任何对象上的任何循环都会循环 在其所有继承的方法上也是如此。