Quero saber como listar todos os métodos disponíveis para um objeto, como por exemplo:
alert(show_all_methods(Math));
Isso deve imprimir:
abs, acos, asin, atan, atan2, ceil, cos, exp, floor, log, max, min, pow, random,round, sin, sqrt, tan, …
Quero saber como listar todos os métodos disponíveis para um objeto, como por exemplo:
alert(show_all_methods(Math));
Isso deve imprimir:
abs, acos, asin, atan, atan2, ceil, cos, exp, floor, log, max, min, pow, random,round, sin, sqrt, tan, …
Respostas:
Você pode usar Object.getOwnPropertyNames()
para obter todas as propriedades que pertencem a um objeto, sejam enumeráveis ou não. Por exemplo:
console.log(Object.getOwnPropertyNames(Math));
//-> ["E", "LN10", "LN2", "LOG2E", "LOG10E", "PI", ...etc ]
Você pode usar filter()
para obter apenas os métodos:
console.log(Object.getOwnPropertyNames(Math).filter(function (p) {
return typeof Math[p] === 'function';
}));
//-> ["random", "abs", "acos", "asin", "atan", "ceil", "cos", "exp", ...etc ]
Nos navegadores ES3 (IE 8 e inferiores), as propriedades dos objetos internos não são enumeráveis. Objetos como window
e document
não são incorporados, são definidos pelo navegador e provavelmente enumeráveis pelo design.
Do ECMA-262 Edição 3 :
Objeto global
Há um objeto global exclusivo (15.1), criado antes do controle entrar em qualquer contexto de execução. Inicialmente, o objeto global possui as seguintes propriedades:• Objetos internos, como Math, String, Date, parseInt, etc. Estes possuem atributos {DontEnum} .
• Propriedades adicionais definidas pelo host. Isso pode incluir uma propriedade cujo valor é o próprio objeto global; por exemplo, no modelo de objeto de documento HTML, a propriedade window do objeto global é o próprio objeto global.À medida que o controle entra nos contextos de execução e quando o código ECMAScript é executado, propriedades adicionais podem ser adicionadas ao objeto global e as propriedades iniciais podem ser alteradas.
Devo salientar que isso significa que esses objetos não são propriedades enumeráveis do objeto Global. Se você examinar o restante do documento de especificação, verá que a maioria das propriedades e métodos internos desses objetos têm o { DontEnum }
atributo definido neles.
Atualização: um colega usuário do SO, CMS, trouxe um bug do IE referente{ DontEnum }
à minha atenção.
Em vez de verificar o atributo DontEnum, o JScript da [Microsoft] pulará qualquer propriedade em qualquer objeto em que haja uma propriedade com o mesmo nome na cadeia de protótipos do objeto que possui o atributo DontEnum.
Em resumo, tenha cuidado ao nomear as propriedades do seu objeto. Se houver uma propriedade ou método de protótipo interno com o mesmo nome, o IE o ignorará ao usar um for...in
loop.
Object.getOwnPropertyNames()
, que retornará propriedades e métodos não enumeráveis.
Object.getOwnPropertyNames(Array.prototype)
?
Não é possível no ES3, pois as propriedades possuem um DontEnum
atributo interno que nos impede de enumerar essas propriedades. O ES5, por outro lado, fornece descritores de propriedades para controlar os recursos de enumeração de propriedades, para que propriedades nativas e definidas pelo usuário possam usar a mesma interface e desfrutar dos mesmos recursos, o que inclui a capacidade de ver propriedades não enumeráveis programaticamente.
A getOwnPropertyNames
função pode ser usada para enumerar todas as propriedades do objeto passado, incluindo aquelas que não são enumeráveis. Em seguida, uma typeof
verificação simples pode ser empregada para filtrar as não funções. Infelizmente, o Chrome é o único navegador em que ele trabalha atualmente.
function getAllMethods(object) {
return Object.getOwnPropertyNames(object).filter(function(property) {
return typeof object[property] == 'function';
});
}
console.log(getAllMethods(Math));
logs ["cos", "pow", "log", "tan", "sqrt", "ceil", "asin", "abs", "max", "exp", "atan2", "random", "round", "floor", "acos", "atan", "min", "sin"]
em nenhuma ordem específica.
var methods = [];
for (var m in obj) {
if (typeof obj[m] == "function") {
methods.push(m);
}
}
alert(methods.join(","));
Dessa forma, você obterá todos os métodos que você pode chamar obj
. Isso inclui os métodos que "herda" de seu protótipo (como getMethods()
em java). Se você quiser apenas ver os métodos definidos diretamente por obj
você, verifique com hasOwnProperty
:
var methods = [];
for (var m in obj) {
if (typeof obj[m] == "function" && obj.hasOwnProperty(m)) {
methods.push(m);
}
}
alert(methods.join(","));
document
ou window
tenho mais sorte. Francamente, é um pouco inesperado, eu não sei por que ele não funciona para Math etc.
document
e window
são objetos com propriedades enumeráveis fornecidas pelo navegador, eles não fazem parte do tempo de execução do script. Objetos nativos são e obviamente as propriedades não são enumeráveis.
O suporte ao navegador mais moderno console.dir(obj)
, que retornará todas as propriedades de um objeto que ele herdou por meio de seu construtor. Consulte a documentação do Mozilla para obter mais informações e suporte atual ao navegador.
console.dir(Math)
=> MathConstructor
E: 2.718281828459045
LN2: 0.6931471805599453
...
tan: function tan() { [native code] }
__proto__: Object
As outras respostas aqui funcionam para algo como Math, que é um objeto estático. Mas eles não funcionam para uma instância de um objeto, como uma data. Eu encontrei o seguinte para trabalhar:
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/
Isso não funcionará para algo como a pergunta original (matemática); portanto, escolha sua solução com base nas suas necessidades. Estou postando isso aqui porque o Google me enviou a essa pergunta, mas eu queria saber como fazer isso para instâncias de objetos.
A resposta curta é que você não pode, porque Math
e Date
(em cima da minha cabeça, tenho certeza que existem outros) não são objetos normais. Para ver isso, crie um script de teste simples:
<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>
Você vê que ele apresenta como um objeto da mesma maneira que o documento em geral, mas quando você realmente tenta ver nesse objeto, vê que é código nativo e algo não exposto da mesma maneira para enumeração.
Math
tem um método estático onde você pode chamar diretamente like Math.abs()
enquanto Date
tem um método estático Date.now()
e também um método de instância em que é necessário criar uma nova instância primeiro var time = new Date()
para chamar 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);
É claro que você precisará filtrar as chaves obtidas para o método estático para obter nomes de métodos reais, porque você também pode obter length, name
que não sejam uma função na lista.
Mas como se queremos obter todo método disponível da classe que estende outra classe?
Claro que você precisará escanear a raiz do protótipo como usar __proto__
. Para economizar seu tempo, você pode usar o script abaixo para obter o método estático e a instância profunda do método.
// 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));
Se você deseja obter métodos da instância criada, não esqueça de passar a instância constructor
.
Acredito que há uma simples razão histórica pela qual você não pode enumerar métodos de objetos internos, como Array, por exemplo. Aqui está o porquê:
Métodos são propriedades do objeto-protótipo, como Object.prototype. Isso significa que todas as instâncias de objetos herdarão esses métodos. É por isso que você pode usar esses métodos em qualquer objeto. Diga .toString (), por exemplo.
Portanto, se os métodos fossem enumeráveis e eu repetiria digitando {a: 123} com: "for (digite {a: 123}) {...}" o que aconteceria? Quantas vezes esse loop seria executado?
Seria iterado uma vez para a chave única 'a' em nosso exemplo. MAS TAMBÉM uma vez para cada propriedade enumerável de Object.prototype. Portanto, se os métodos fossem enumeráveis (por padrão), qualquer loop sobre qualquer objeto também repetiria todos os seus métodos herdados.
Object.getOwnPropertyNames(Array.prototype)
, por exemplo