Share via


El cambio que no debería afectarnos

Me he topado con un cliente afectado por un cambio que ha habido en IE8 por el cual, así a bote pronto, parece que nadie debería verse afectado. Resulta que en IE8 han cambiado el nombre de las funciones que se generan internamente cuando agregamos un “event handler” a un determinado elemento. Mirad el siguiente código:

    1: <script language="javascript">  
    2: function ejemplo() 
    3: { 
    4: alert(ejemplo.caller.toString()); 
    5: } 
    6: </script>
    7: <a href="#1" onclick="ejemplo();">Ejemplo</a> 

Pues bien, en IE6, el mensaje de alerta mostrará el siguiente texto:

    1: function anonymous()
    2: {
    3:     sample();
    4: }

Mientras que en IE8, el mensaje mostrará el siguiente texto:

    1: function onclick()
    2: {
    3: sample();
    4: }

La propiedad caller nos retorna un puntero a la función que nos invocó (el llamador). Se la ejecución se ha iniciado en el nivel más alto, “caller” retornará un null. Convirtiendo el objeto a string, obtenemos el código decompilado que forma la función.

Imaginemos la siguiente función que pretende diferenciar si ha sido llamada desde el evento “onclick” o ha sido invocada directamente:

    1: function hacerAlgo() 
    2: {
    3:     if(hacerAlgo.caller != null && hacerAlgo.caller.toString().indexOf("onclick") > -1) 
    4:     { 
    5:         alert("Nos han llamado de onclick"); 
    6:     } 
    7:     else 
    8:     { 
    9:         alert("Nos han llamado directamente"); 
   10:     }
   11: }

Por supuesto, este código no funcionará en un navegador IE6 debido al cambio en el nombre de la función generada como hemos visto previamente. Bien, más allá de la anécdota del cambio de nombre, en este post vengo a reflejar qué no hacer para evitar vernos afectados por un cambio que, a priori no debería importarnos. Desde mi punto de vista, el basar en el código decompilado del llamador la decisión sobre si nos invocan desde un evento onclick, es una vuelta de rosca demasiado compleja cuando podemos utilizar el objeto “event” que directamente nos aporta mucha más información y acceso a propiedades del evento que seguramente sean útiles.

El código previo puede cambiarse por el siguiente, mucho más elegante en mi opinión, y más alineado con lo que se quiere saber (si se ha producido el evento onclick):

    1: function hacerAlgo2() 
    2: {
    3:     if(event!=null && event.type=="click") 
    4:     { 
    5:         alert("Nos han llamado de onclick"); 
    6:     } 
    7:     else 
    8:     { 
    9:         alert("Nos han llamado directamente o desde otro evento"); 
   10:     } 
   11:     }

Puesto que el tipo de evento (propiedad type del objeto event) es algo que forma parte intrínseca y pública del evento y constituye un contrato de acuerdo al DOM, si en alguna de las implementaciones posteriores se modificara (cosa que dudo), se pensará en la manera de mitigar a los clientes existentes o se realizarán acciones para que puedan convivir ambos modelos.

Corolario: No reinventes la rueda, hombre!