Evitar el uso de eval() en Javascript

Hoy en el trabajo he descubierto que la función eval() de Javascript y Firebug se llevan muy mal. Tan mal que no conseguía depurar una clase que estoy desarrollando. Googleando un poco he conseguido encontrar varias formas de evitar eval() y algunos motivos por lo que es recomendable evitar su uso.

El funcionamiento de eval() es el siguiente:

  1. Se convierte el argumento en un String.
  2. Se parsea el String y se convierte en código Javascript.
  3. Se ejecuta el código Javascript resultante.

Evidentemente saltarse los pasos 1 y 2 mejora el rendimiento. Además evita esos problemas “raros” que he comentado antes con Firebug.

En concreto los problemas con los que me he encontrado incluían los siguientes usos de eval:

  • Asignar una propiedad a un objeto cuyo nombre está almacenado en un String.
  • Llamar a una función cuyo nombre está almacenado en un String.
  • Crear un objeto de una clase cuyo nombre está almacenado en un String.

Es decir, tres casos muy parecidos que se reducen a uno solo, acceder a variables cuyo nombre conocemos a posteriori. Para solucionar esto basta con saber que hay varias formas de acceder a una propiedad de un objeto en Javascript. La típica:

  1. objeto.atributo = valor

y la no tan típica:

  1. var nombreDelAtributo="atributo";
  2. objeto[nombreDelAtributo] = valor;

Ahora solo falta saber otra cosa. Cualquier variable se puede acceder también como un atributo del objeto window, un ejemplo:

  1. var cadena = "Hola mundo!";
  2. alert(window.cadena); //mostrará un alert con "Hola mundo!"
  3. alert(window[‘cadena’]); //también mostrara un alert con "Hola mundo!"

Ahora veamos algunos ejemplos de usos de eval() y otras formas de avordar el mismo problema.

  1. /*
  2. *asignar un valor a un atributo cuyo nombre no conocemos a priori
  3. */
  4. eval(‘objecto.’ + nombreDelAtributo + ‘=valorDelAtributo’);
  5. //se podría cambiar por
  6. objeto[nombreDelAtributo] = valorDelAtributo;
  7.  
  8. /*
  9. * Llamar a un metodo de un objeto estando el nombre del metodo almacenado en una variable
  10. */
  11.  
  12. eval(‘objeto.’ + nombreDelMetodo + ‘(argumento)’);
  13. //podría ser
  14. objeto[nombreDelMetodo](argumento);
  15.  
  16. /*
  17. * Crear un objeto de una clase teniendo el nombre de la clase en una variable
  18. */
  19.  
  20. eval(‘var objeto = new ‘ + nombreDeLaClase + ‘()’);
  21. //sería
  22. var objeto = new window[nombreDeLaClase]();

En el último ejemplo podemos hacer esto por que una clase es también una variable del programa, y como tal se almacena como un atributo del objeto window.

Y vosotros, ¿usáis eval() en vuestro código? ¿conocíais estas soluciones?

No hay posts relacionados.

Tags: , ,

7 comentarios en “Evitar el uso de eval() en Javascript”

  1. Buzu Ha dicho:

    Hola, pues interesante el articulo, yo siempre he evitado eval por los supuestos riesgos en la seguridad. Conocía los métodos de acceder variables y los uso muy seguido, especialmente cuando estoy creando objetos, aun que no había notado la relación que hay entre estos y eval. Muy interesante sin duda.

    Por cierto, sin afán de iniciar un debate, pero que no se supone que Javascript no está basado en clases sino en prototipos? bueno, eso es solo un comentario, pero en realidad no es muy importante.

    Saludos.

  2. Francisco Ha dicho:

    Hola Buzu,

    Sí, llevas razón, está basado en prototipos, pero usando algún framework, como Prototype, se consigue una abstracción mayor, que oculta el uso de los prototipos al programador y que hace la orientación a objetos de Javascript más parecida a la de otros lenguajes como Java. Por esto es por lo que he dicho que estoy haciendo una “clase” ;)

    Saludos!

  3. Erikcq Ha dicho:

    Oye es muy buena tu explicacion pero tengo un pequeño problema estoy usando Ajax para pasar un arreglo multidimensional desde un servlet en java hacia una pagina web el servlet me regresa un texto el cual yo interpreto como un comando javascript ejem Array(”tex1″, “tex2″, “texN”), el cual si es simple lo hace perfectamente, pero si paso un texto que simule un arreglo multidimensional no me funciona, que otra instruccion puedo usar para representar un texto como comando de javascript.

  4. Francisco Ha dicho:

    @Erikcq Si te entiendo bien lo que haces es devolver un script Javascrip desde un servlet tras una petición AJAX. ¿Has probado a devolver los datos en otro formato como JSON o XML y crear ese array (o arreglo, como prefieras) desde Javascript? A mí me parece la forma más simple y es lo que suelo hacer.

    Un saludo.

  5. Xavo Mora Ha dicho:

    EXCELENTE. estaba usando una psclase con jquery al que le pasaba funcion como parametro y al hacer click en mya_b ejecutar la funcion y la matriz:

    mya_b.bind("click",function(){
    var thisreturn = new Array();
    $(par).each(function (i, n){
    thisreturn[n]= $("#boxiframe").contents().find("#"+n).val(); })
    window[func](thisreturn);
    });

    Muchas gracias

  6. Lucia Ha dicho:

    Hola.

    Necesito ejecutar una función javascript cuyo nombre esta definido en una variable. Ha dicha función la tengo que pasar una serie de parámetros. Segun he estado viendo en lo publicado tendría que hacer algo asi

    /*
    * Llamar a un metodo de un objeto estando el nombre del metodo almacenado en una variable
    */

    eval(‘objeto.’ + nombreDelMetodo + ‘(argumento)’);
    //podría ser
    objeto[nombreDelMetodo](argumento);

    Pero tengo una duda, ¿que es objeto? he realizado una prueba y no me funciona.

    Muchas gracias.

  7. Lucia Ha dicho:

    Hola de nuevo!!!

    Ya me funciona. En vez de objeto puse window y ya hace lo que yo quiero.

    Muchas gracias por este articulo.

    Un saludo.

Deja un comentario