Answers:
您可以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),它在控制进入任何执行上下文之前创建。最初,全局对象具有以下属性:•内置对象,例如Math,String,Date,parseInt等。这些对象具有属性{DontEnum}。
•其他主机定义的属性。这可能包括一个属性,其值为全局对象本身。例如,在HTML文档对象模型中,全局对象的window属性是全局对象本身。当控件进入执行上下文时,以及在执行ECMAScript代码时,可以将其他属性添加到全局对象,并且可以更改初始属性。
我应该指出,这意味着这些对象不是Global对象的不可枚举的属性。如果翻阅规范文档的其余部分,您将看到这些对象的大多数内置属性和方法{ DontEnum }
在其上设置了属性。
更新:一位SO用户CMS带来了一个与我有关{ DontEnum }
的IE错误。
[Microsoft] JScript不会检查DontEnum属性,而是跳过对象原型链中具有属性DontEnum的同名属性的任何对象中的任何属性。
简而言之,在命名对象属性时要当心。如果存在具有相同名称的内置原型属性或方法,则IE在使用for...in
循环时将跳过它。
Object.getOwnPropertyNames()
,这甚至会返回不可枚举的属性和方法。
Object.getOwnPropertyNames(Array.prototype)
吗?
对于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"]
没有特别的顺序登录。
var methods = [];
for (var m in obj) {
if (typeof obj[m] == "function") {
methods.push(m);
}
}
alert(methods.join(","));
这样,您将获得可以调用的所有方法obj
。这包括它从其原型“继承”的方法(如getMethods()
Java)。如果您只想查看那些直接定义的方法,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
获得更多的运气时。坦率地说这是一个有点意外,我不知道为什么它不会为数学等方面的工作
document
和window
是浏览器提供的具有可枚举属性的对象,它们不是脚本运行时的一部分。显然,本机对象是不可枚举的。
这里的其他答案适用于像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向我发送了此问题,但我想知道如何针对对象实例执行此操作。
简短的答案是您不能这样做,因为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>
您看到它作为对象呈现的方式与文档的总体操作方式相同,但是当您实际尝试查看该对象时,您看到的是它的本机代码,并且某些东西没有以相同的方式进行枚举。
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__
。为了节省时间,您可以使用下面的脚本获取静态方法和深层方法实例。
// 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
它的。
我相信有一个简单的历史原因,导致您无法枚举诸如Array之类的内置对象的方法。原因如下:
方法是原型对象的属性,例如Object.prototype。这意味着所有对象实例都将继承这些方法。这就是为什么您可以在任何对象上使用这些方法的原因。例如说.toString()。
因此IF方法是可枚举的,我将用{for(key in {a:123}){...}“遍历说{a:123}会发生什么?该循环执行多少次?
在我们的示例中,将对单个键“ a”进行一次迭代。但对于Object.prototype的每个可枚举属性也要一次。因此,如果方法是可枚举的(默认情况下),那么任何对象上的任何循环都会遍历其所有继承的方法。
Object.getOwnPropertyNames(Array.prototype)
,例如