Comment fonctionne le Javascript en ligne (en HTML)?

129

Je sais que c'est une mauvaise pratique. N'écrivez pas de code comme celui-ci si possible.

Bien sûr, nous nous trouverons toujours dans des situations où un extrait intelligent de Javascript en ligne peut résoudre un problème rapidement.

Je poursuis cette requête dans l'intérêt de comprendre pleinement ce qui se passe (et les pièges potentiels) quand quelque chose comme ceci est écrit:

<a href="#" onclick="alert('Hi')">Click Me</a>

Autant que je sache, c'est fonctionnellement le même que

<script type="text/javascript">
   $(function(){ // I use jQuery in this example
       document.getElementById('click_me').onclick = 
           function () { alert('Hi'); };
   });
</script>
<a href="#" id="click_me">Click Me</a>

En extrapolant à partir de cela, il semble que la chaîne affectée à l'attribut onclicksoit insérée dans une fonction anonyme qui est affectée au gestionnaire de clics de l'élément. Est-ce vraiment le cas?

Parce que je commence à faire des choses comme ça:

<a href="#" onclick="$(this).next().fadeIn(); return false;">Display my next sibling</a> <!-- Return false in handler so as not to scroll to top of page! --> 

Ce qui fonctionne. Mais je ne sais pas à quel point c'est un hack. Cela semble suspect car il n'y a aucune fonction apparente qui est renvoyée!

Vous pourriez demander, pourquoi faites-vous ça, Steve? Inline JS est une mauvaise pratique!

Eh bien, pour être tout à fait honnête, je suis fatigué d'éditer trois sections différentes de code juste pour modifier une section d'une page, en particulier lorsque je ne fais que prototyper quelque chose pour voir si cela fonctionnera. C'est tellement plus facile et parfois même logique que le code spécifiquement lié à cet élément HTML soit défini directement dans l'élément: quand je décide 2 minutes plus tard que c'était une idée terrible, terrible, je peux détruire le div entier (ou peu importe ) et je n'ai pas un tas de mystérieux crottes JS et CSS qui traînent dans le reste de la page, ralentissant très légèrement le rendu. Ceci est similaire au concept de localité de référence, mais au lieu de manquer de cache, nous examinons les bogues et le gonflement du code.

Steven Lu
la source
3
Vous avez raison, c'est une fonction anonyme.
bhamlin
1
Vous devrez accrocher la requête #click_mesur l'événement DOMready ou placer le script après le nœud.
Bergi
1
Dans une console, faites document.getElementById("click_me").onclick;. Ou alertez-le. Vous verrez que c'est dans une fonction.
D. Strout

Réponses:

96

Vous l'avez presque correct, mais vous n'avez pas pris en compte la thisvaleur fournie au code en ligne.

<a href="#" onclick="alert(this)">Click Me</a>

est en fait plus proche de:

<a href="#" id="click_me">Click Me</a>
<script type="text/javascript">
document.getElementById('click_me').addEventListener("click", function(event) {
    (function(event) {
        alert(this);
    }).call(document.getElementById('click_me'), event);
});
</script>

Les gestionnaires d'événements en ligne sont définis comme étant thiségaux à la cible de l'événement. Vous pouvez également utiliser une fonction anonyme dans un script en ligne

<a href="#" onclick="(function(){alert(this);})()">Click Me</a>
apsillers
la source
7
Le script doit venir après la balise, sinon la balise n'existe pas lorsqu'elle est exécutée - je suggère de changer votre réponse pour refléter cela.
undefined
comment propager le eventavec un inline onclick='myFunction(event)'??
oldboy
9

Ce que fait le navigateur lorsque vous avez

<a onclick="alert('Hi');" ... >

est de définir la valeur réelle de "onclick" sur quelque chose comme:

new Function("event", "alert('Hi');");

Autrement dit, il crée une fonction qui attend un paramètre "événement". (Eh bien, IE ne le fait pas; cela ressemble plus à une simple fonction anonyme.)

Pointu
la source
2
Ah. Je peux donc réellement utiliser la variable eventpour récupérer l'événement (et l'élément d'origine à partir de celui-ci via event.target), à partir de mon extrait JS en ligne! Cool.
Steven Lu
1
IE ne transmet vraiment pas le eventparamètre, mais si vous l'utilisez à l' eventintérieur de cette fonction anonyme, IE le comprendra comme l'objet d'événement réel. Comme la fonction anonyme est définie comme une propriété d' windowobjet dans IE, elle verra cela comme window.event.
rdleal
8

Il semble y avoir beaucoup de mauvaises pratiques lancées autour des attributs du gestionnaire d'événements. Une mauvaise pratique consiste à ne pas connaître et utiliser les fonctionnalités disponibles là où cela est le plus approprié. Les attributs d'événement sont entièrement des normes documentées du W3C et il n'y a rien de mauvais à leur sujet. Ce n'est pas différent de placer des styles en ligne, qui est également documenté par le W3C et peut être utile dans le temps. Que vous le placiez ou non dans des balises de script, il sera interprété de la même manière.

https://www.w3.org/TR/html5/webappapis.html#event-handler-idl-attributes

Daniel B
la source
2
Oui, je suis enclin à être d'accord, et j'ai même fourni des «raisons» raisonnables pour lesquelles ce type particulier d'utilisation de code en ligne pourrait être justifié dans certaines situations. Mais la réalité est que lorsqu'une application (application Web ou autre) atteint une certaine complexité (et cela ne prend généralement pas beaucoup de temps ou de travail à atteindre), avoir de petits extraits de code éparpillés sur la mise en page HTML est susceptible de être architecturalement défectueux du point de vue de la maintenabilité. En commençant même à coder directement JS dans un fichier HTML, par exemple, on tente la pente glissante de la spaghettification.
Steven Lu
1
Et c'est un argument valable contre, un argument sur lequel je suis d'accord. Je n'ajoute généralement pas de script en ligne, ni de style pour ce sujet, moi-même. Mais les gens ont des goûts différents. Beaucoup, par exemple, aiment ajouter des balises de script et de style dans la section corps, je ne peux pas le supporter. Mais c'est valable et certaines personnes l'aiment. Ce que les coutures aiment bad practice/spaghettificationpour certains, l'est good practice/structurepour d'autres.
Daniel B
J'ai regardé github.com/styled-components/styled-components et si vous combinez cela avec react, par exemple, nous avons maintenant tout ce qui est associé à un composant de votre application vivant réellement ensemble (espérons-le pacifiquement) au même endroit. Et ça n'a pas l'air terrible non plus. On a l'impression de progresser. Dans cette optique, le brouillage des styles et du code en ligne dans HTML n'est pas la bonne façon (jusqu'à présent, cela semble être le brouillage du HTML et des styles dans le code JS).
Steven Lu le
5

La meilleure façon de répondre à votre question est de la voir en action.

<a id="test" onclick="alert('test')"> test </a> 

Dans le js

var test = document.getElementById('test');
console.log( test.onclick ); 

Comme vous le voyez dans console, si vous utilisez chrome, il imprime une fonction anonyme avec l'objet événement transmis, bien que ce soit un peu différent dans IE.

function onclick(event) {
   alert('test')
}

Je suis d'accord avec certains de vos points concernant les gestionnaires d'événements en ligne. Oui, ils sont faciles à écrire, mais je ne suis pas d'accord avec votre point de vue sur la nécessité de changer le code à plusieurs endroits, si vous structurez bien votre code, vous ne devriez pas avoir besoin de le faire.

aziz punjani
la source
Je pense que quelque chose comme <button onclick="login()"> test login </button>est parfaitement bien pour le prototypage. Vous voulez tester quelque chose qui nécessite une interaction de l'utilisateur dès maintenant, et vous allez simplement le supprimer plus tard de toute façon. Pourquoi écrire du code supplémentaire partout?
Dagg Nabbit
Ce n'est pas du code supplémentaire, juste une fonction anonyme supplémentaire. Et ce n'est pas partout, c'est en fait tout au même endroit, dans les balises de script.
aziz punjani
Je ne suis pas sûr que nous partagions la même idée de «bien structurer votre code». Si vous liez l'interface utilisateur à vos "fonctions de base" à l'endroit où vivent vos fonctions de base, cela me semble être un arrangement de couplage pire que de simplement les lier dans l'interface utilisateur. Je garde généralement tous les éléments de liaison de l'interface utilisateur séparés des éléments de base, et j'ai le sentiment que l'OP pourrait aussi ...
Dagg Nabbit
3

Cela semble suspect car il n'y a aucune fonction apparente qui est renvoyée!

C'est une fonction anonyme qui a été attachée à l'événement de clic de l'objet.

pourquoi fais-tu ça, Steve?

Pourquoi diable êtes-vous doi ..... Ah tant pis, comme vous l'avez mentionné, c'est vraiment une mauvaise pratique largement adoptée :)

mattytommo
la source
3

Essayez ceci dans la console:

var div = document.createElement('div');

div.setAttribute('onclick', 'alert(event)');

div.onclick

Dans Chrome, cela montre ceci:

function onclick(event) {
  alert(event)
}

... et la namepropriété non standard de div.onclickis "onclick".

Donc, que ce soit ou non anonyme dépend de votre définition de «anonyme». Comparez avec quelque chose comme var foo = new Function(), où foo.nameest une chaîne vide, et foo.toString()produira quelque chose comme

function anonymous() {

}
Dagg Nabbit
la source
Cela a commencé comme un commentaire sur la réponse de Pointy, mais n'a vraiment pas fonctionné comme un commentaire. C'est vraiment la meilleure réponse ici, je pense.
Dagg Nabbit