2008-11-08 8 views
28

¿Hay alguna forma de obtener todos los métodos (privados, privilegiados o públicos) de un objeto javascript desde dentro? Aquí está el objeto de muestra:Reflexión de Javascript

var Test = function() { 
// private methods 
    function testOne() {} 
    function testTwo() {} 
    function testThree() {} 
// public methods 
    function getMethods() { 
     for (i in this) { 
     alert(i); // shows getMethods, but not private methods 
     } 
    } 
    return { getMethods : getMethods } 
}(); 

// should return ['testOne', 'testTwo', 'testThree', 'getMethods'] 
Test.getMethods(); 

El problema actual es el código en getMethods(), el ejemplo simplificado devolverá sólo los métodos públicos, pero no a los privados.

edit: mi código de prueba puede (o no) ser demasiado complicado para lo que espero obtener. dado el siguiente:

function myFunction() { 
    var test1 = 1; 
    var test2 = 2; 
    var test3 = 3; 
} 

hay una manera de averiguar qué existen las variables en myFunction() desde dentro myFunction(). el pseudocódigo se vería así:

function myFunction() { 
    var test1 = 1; 
    var test2 = 2; 
    var test3 = 3; 

    alert(current.properties); // would be nice to get ['test1', 'test2', 'test3'] 
} 

Respuesta

28

La razón técnica por la que esos métodos están ocultos es doble.

Primero, cuando ejecuta un método en el objeto Test, "this" será el objeto sin tipo devuelto al final de la función anónima que contiene los métodos públicos por el Module Pattern.

En segundo lugar, los métodos testOne, testTwo y testThree no están adjuntos a un objeto específico, y existen solo en el contexto de la función anónima. Puede adjuntar los métodos a un objeto interno y luego exponerlos a través de un método público, pero no sería tan limpio como el patrón original y no será útil si obtiene este código de un tercero.

El resultado sería algo como esto:

var Test = function() { 
    var private = { 
     testOne : function() {}, 
     testTwo : function() {}, 
     testThree : function() {} 
    }; 

    function getMethods() { 
     for (i in this) { 
      alert(i); // shows getMethods, but not private methods 
     } 
     for (i in private) { 
      alert(i); // private methods 
     } 
    } 
    return { getMethods : getMethods } 
}(); 

// will return ['getMethods', 'testOne', 'testTwo', 'testThree'] 
Test.getMethods(); 

edición:

Por desgracia, no. No se puede acceder al conjunto de variables locales a través de una sola palabra clave automática.

Si elimina la palabra clave "var", se adjuntarán al contexto global (normalmente el objeto de la ventana), pero ese es el único comportamiento que conozco que es similar a lo que está describiendo. Sin embargo, habría muchas otras propiedades y métodos en ese objeto si hicieras eso.

+1

ya, eso es lo que temía. supongo que las opciones son la estructura que publicaste (ugh messsy), o simplemente haciendo que los métodos que quieres estén disponibles sean "públicos". oh bien :) – Owen

0

Si llama a getMethods() así, ¿no es estático? ¿Seguramente necesitaría iniciar correctamente la clase para que this funcione como se espera?

var t = new Test(); 
t.getMethods(); 

Si eso no funciona, por favor, eche un vistazo a la JS Serializer. Lo usé hace un tiempo para depurarme un poco y creo que funcionó para vars privados.

+2

la sintaxis anterior es equivalente a: Prueba var = new Object(); Test.getMethods(); – Owen

2

Javascript realmente no tiene la noción de nada privado. Debido a eso, javascript no tiene una API de reflexión como tal. La técnica que está utilizando no los hace privados, sino que los hace inaccesibles; están escondidos, no son privados. Creo que podrías manejar algo al poner esos métodos en algún lugar de forma manual.

+6

B no sigue de A. Los idiomas pueden tener una API de reflexión con o sin privacidad de datos. (Las variables que tiene ni siquiera están "ocultas" o "privadas", solo son locales). Python no tiene privacidad de datos, pero admite una poderosa reflexión. –

+1

- 1. La respuesta es engañosa. Vea el comentario de Glenn "B no sigue de A. Los idiomas pueden tener una API de reflexión con o sin privacidad de datos" para más detalles. – andy

+1

JavaScript no puede usar específicamente identificadores "privados" como Java, pero ciertamente tiene la noción de variables y métodos privados. Cualquier cosa declarada como "var a = 1" es implícitamente privada dentro de una función, ya que no se puede acceder desde el exterior. –

1

Parte del problema con su código de prueba es que la prueba es el objeto creado por su declaración de devolución: "{ getMethods : getMethods }" No tiene métodos testOne, testTwo o testThree; en cambio, solo están disponibles dentro del mismo espacio de nombres que la función getMethods original.

+0

correcto, entonces estoy buscando una manera de acceder a ese espacio de nombres dentro de getMethods(). En esencia, esperaba perderme alguna referencia teórica (como esta en otros idiomas) – Owen

1

puede utilizar var that = this; truco:

var Test = function() { 
    var that = this; 
    function testOne() {} 
    function testTwo() {} 
    function testThree() {} 
    function getMethods() { 
     for (i in that) { 
     alert(i); 
     } 
    } 
    return { getMethods : getMethods } 
}(); 
+1

que está imprimiendo todos los miembros del objeto de contexto (por ejemplo, ventana) –

1

Con un pequeño cambio a la forma en que la función está definida se puede lograr lo que quiere. Envolver la aplicación real de la función en un objeto literal sería el siguiente aspecto:

(function() { 
    var obj = { 
    // private methods 
    testOne: function() {}, 
    testTwo : function() {}, 
    testThree: function() {}, 
    // public methods 
    getMethods : function() { 
     for (i in this) { 
     alert(i); // shows getMethods, but not private methods 
     } 
    } 
    }; 
    return { getMethods : function(){return obj.getMethods();} } 
})(); 
4

De http://netjs.codeplex.com/SourceControl/changeset/view/91169#1773642

//Reflection 

~function (extern) { 

var Reflection = this.Reflection = (function() { return Reflection; }); 

Reflection.prototype = Reflection; 

Reflection.constructor = Reflection; 

Reflection.getArguments = function (func) { 
    var symbols = func.toString(), 
     start, end, register; 
    start = symbols.indexOf('function'); 
    if (start !== 0 && start !== 1) return undefined; 
    start = symbols.indexOf('(', start); 
    end = symbols.indexOf(')', start); 
    var args = []; 
    symbols.substr(start + 1, end - start - 1).split(',').forEach(function (argument) { 
     args.push(argument); 
    }); 
    return args; 
}; 

extern.Reflection = extern.reflection = Reflection; 

Function.prototype.getArguments = function() { return Reflection.getArguments(this); } 

Function.prototype.getExpectedReturnType = function() { /*ToDo*/ } 

} (this); 
+0

¿Has probado esto? – will

+0

¡Visite http://netjs.codeplex.com/! ¡Gracias por las palabras amables! – Jay