onclick="" frente al controlador de eventos
Si quiero que se ejecute una función, prefiero hacer js en línea:
<p id="element" onclick="doSomething();">Click me</p>
porque es más fácil de depurar.
Sin embargo, escucho a gente decir que no use js en línea y lo hago:
document.getElementById('element').onclick = doSomething;
¿Por qué se recomienda el detector de eventos js?
Un gran argumento en contra de los controladores de eventos en línea, y el argumento que se aborda en las otras respuestas aquí, es la separación de presentación y lógica .
Sin embargo, en realidad hay un problema mayor en mi opinión: la forma algo esquiva de cómo se evalúan los controladores de eventos en línea.
Como sabrá, el contenido de los on*
atributos se utilizará como cuerpo de la función del controlador de eventos. ¿Pero qué características tiene esta función?
Una de las sorprendentes es que las propiedades de algunos elementos ancestros y del propio elemento están en el alcance del controlador de eventos en línea.
<form>
<input name="foo" />
<button type="button" onclick="console.log(foo); console.log(window.foo);">
Click me
</button>
<div onclick="console.log(foo);">Click me as well!</div>
</form>
Al hacer clic en los button
registros
<input name="foo"></input>
undefined
en la consola. El hecho de que así window.foo
sea undefined
le indica que no existe una variable global foo
. foo
Entonces, ¿de dónde viene la variable ? ¿Por qué console.log(foo)
registra el elemento de entrada y no arroja un error de referencia?
Porque las propiedades del form
elemento están en el alcance del controlador de eventos y el form
elemento tiene una propiedad para cada elemento de control de formulario con nombre que contiene. Puedes probar esto fácilmente con console.log(document.querySelector('form').foo)
.
Ahora, al hacer clic en el div
elemento se genera un error de referencia:
ReferenceError: foo is not defined
Entonces, aparentemente, el form
elemento está solo dentro del alcance de los elementos de control de formulario, no en ningún descendiente. ¿Qué tan confuso es eso?
De manera similar, las propiedades deldocument
objeto también están dentro del alcance de los controladores de eventos en línea, lo que puede generar algunos errores sorprendentes (¿sabías que document
tiene una propiedad plugins
?).
La forma exacta en que se evalúan los controladores de eventos en línea está formalizada en la especificación HTML5 . Tenga un bucle en el paso 10 en particular donde se describe la creación de la cadena de alcance.
Conclusión :
Debido a esta conexión implícita entre elementos y controladores de eventos en línea, los errores pueden ser muy difíciles de rastrear. Por supuesto, está bien utilizar controladores de eventos en línea si sólo quieres probar algo. Pero usarlos en código de producción conlleva un mayor costo de mantenimiento.
Los artículos en quirksmode.org explican muy bien las diferentes formas de vincular controladores de eventos y sus (des)ventajas.
Básicamente tiene que ver con mantener todo separado, creo. Así que mantenga HTML/CSS/JS separados. Hace que su HTML esté más ordenado y, creo, más fácil de navegar sin él.
Luego, cuando/si necesita realizar cambios grandes, tiene suficiente espacio para tener que cambiar el JS en línea a un archivo externo de todos modos O si desea aplicar la misma función a más de un botón, entonces es menos código. Y menos código es un lugar más feliz
Si tiene sus archivos JS correctamente y bien documentados, será más fácil que una persona externa los navegue.
Hay muchas razones para evitar JavaScript en línea y una de las más importantes es la capacidad de mantenimiento del código.
Un ejemplo rápido (estoy usando jQuery simplemente con fines de demostración).
<p class="element" onclick="doSomething();">Click me</p>
<p class="element" onclick="doSomething();">Click me</p>
<p class="element" onclick="doSomething();">Click me</p>
<p class="element" onclick="doSomething();">Click me</p>
<p class="element" onclick="doSomething();">Click me</p>
<p class="element" onclick="doSomething();">Click me</p>
¿Qué pasa si de repente recibes una solicitud para cambiar todos tus párrafos para ejecutar otra función? En su ejemplo, tendría que cambiar todo manualmente en su código HTML. Sin embargo, si elige separar HTML de JavaScript, simplemente puede hacerlo así.
<p class="element">Click me</p>
<p class="element">Click me</p>
<p class="element">Click me</p>
<p class="element">Click me</p>
<p class="element">Click me</p>
<p class="element">Click me</p>
$('.element').bind('click', doSomethingElse);
El código HTML también es más limpio, lo que permite a los diseñadores centrarse exclusivamente en el diseño sin temor a romper algo mientras trabajan en un proyecto en el que también participan otras personas.
EDITAR: Proporcionando un ejemplo para mi comentario a continuación.
Project = {
// All the variables/constants/objects that need to be globally accessible inside the Project object.
init : function(){
// Main entry point...
this.MainMenu.init();
// Rest of the code which should execute the moment Project is initiated.
}
}
Project.MainMenu = {
// All the variables/constants/objects that need to be accessible only to MainMenu.
init : function(){ // Is run immediatelly by Project.init()
// Event handlers relevant to the main menu are bound here
// Rest of the initialization code
}
}
Project.SlideShow = {
// All the variables/constants/objects that need to be accessible only to SlideShow.
init : function(){ // Is run only on pages that really require it.
// Event handlers for the slideshow.
}
}