Ir directamente al contenido de esta página
Cuando se enfrentan a un JavaScript, lo navegadores comienzan a interpretar las líneas de código en el momento mismo en el que las descargan. Esto supone que podemos obtener errores inesperados. El ejemplo clásico es addEventListener
. Supongamos, por ejemplo, que tenemos esta línea de código:
document.getElementById('enviar').addEventListener('click',validar,false);
Lo que hace es añadir una escucha a un botón identificado como enviar
, para lanzar la función validar
en el momento en que el usuario haga clic en el mismo, y así prescindir del atributo onclick
. La línea es correcta, el botón existe y está correctamente identificado, pero ocurre que la función no se ejecuta. ¿Por qué? Pues lo más común es que el script haya sido vinculado en la cabecera del documento. Así, el navegador lee la líneas de JavaScript y la ejecuta inmediatamente, antes de que haya cargado la parte del documento en la que existe el botón.
La forma más sencilla de evitar este problema es colocar la llamada al archivo .js justo antes del cierre del elemento body
, para asegurarse de que todos los posibles elementos sobre los que vaya a trabajar el script se han cargado previamente. Sin embargo, desde el punto de vista del código semántico, el body
debe incluir los contenidos del documento, no un script, que pertenece a la capa de comportamientos. Su ubicación correcta es, por tanto, el head
.
Lo que se hace es incluir los enunciados en una función y especificar que ésta se ejecute cuando el documento haya terminado de cargar. Eso se puede lograr por medio de una línea como ésta:
window.onload = nombre_de_la_funcion;
Sencillo, ¿verdad?
¿Pero qué ocurre si necesito lanzar más de una función? El primer impulso es hacer algo como esto:
window.onload = funcion_primera;
window.onload = funcion_segunda;
window.onload = funcion_tercera;
Sí, todos hemos sido alguna vez así de inocentes, hasta que chocamos con la realidad representada por este ejemplo.
El script del ejemplo es éste:
function funcion_primera(){ alert("Se ha lanzado la PRIMERA función");}
function funcion_segunda(){ alert("Se ha lanzado la SEGUNDA función");}
function funcion_tercera(){ alert("Se ha lanzado la TERCERA función");}
window.onload = funcion_primera;
window.onload = funcion_segunda;
window.onload = funcion_tercera;
Como vemos, sólo se lanza la última función.
¿A qué se debe? Pues porque aunque al mirar las últimas líneas nos parece que al navegador le decimos algo como «cuando los contenidos de la ventana se carguen me lanzas esta función, y ésta, y ésta», este método de programación intuitiva choca con lo que técnicamente estamos diciendo. Lo que en rigor decimos con window.onload = funcion_primera;
es «al método onload
del objeto window
le asigno el valor de funcion_primera
». Podría parecer que es una mera diferencia de jerga, pero no es así, porque al escribir window.onload = funcion_segunda;
, volvemos a decir lo mismo para la segunda función, por lo que reasignamos un valor para el mismo método del mismo objeto, con lo que el valor anterior se pierde. Es como si declaráramos una variable varias veces: sólo se mantendría el último valor especificado.
El problema reside entonces en que window.onload
sólo se puede asignar de manera efectiva una vez. Se podría, por tanto asignar a una única función que lanzase todas las demás, en el orden deseado:
function funcion_primera(){ alert("Se ha lanzado la PRIMERA función");}
function funcion_segunda(){ alert("Se ha lanzado la SEGUNDA función");}
function funcion_tercera(){ alert("Se ha lanzado la TERCERA función");}
function lanzadera(){
funcion_primera();
funcion_segunda();
funcion_tercera();
}
window.onload = lanzadera;
Como se ve en este segundo ejemplo, funciona.
No obstante, no es la solución ideal a menos que todas y cada una de las funciones que queramos lanzar estén en el mismo archivo .js. Con diversos scripts vinculados nos encontraríamos de nuevo con la situación inicial. Por ello, es más eficaz asignar el evento load
a window
con la función que se desea ejecutar. Como se puede asignar una escucha de forma independiente para cada función, desde diversos .js se pueden lanzar diversas funciones. En este último ejemplo vinculo tres .js independientes, uno con cada función, y en cada uno añado unas líneas como éstas:
if (document.addEventListener){
window.addEventListener('load',la_funcion_que_sea,false);
} else {
window.attachEvent('onload',la_funcion_que_sea);
}
El resultado es el mismo que en el segundo ejemplo, pero la solución es más flexible.