Wie funktioniert Inline-Javascript (in HTML)?

129

Ich weiß, dass dies eine schlechte Praxis ist. Schreiben Sie keinen solchen Code, wenn dies überhaupt möglich ist.

Natürlich befinden wir uns immer in Situationen, in denen ein cleverer Ausschnitt aus Inline-Javascript ein Problem schnell beheben kann.

Ich verfolge diese Abfrage, um vollständig zu verstehen, was passiert (und welche potenziellen Gefahren es gibt), wenn so etwas geschrieben wird:

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

Soweit ich das beurteilen kann, ist dies funktional dasselbe wie

<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>

Aus diesem Grund scheint es, dass die dem Attribut zugewiesene Zeichenfolge onclickin eine anonyme Funktion eingefügt wird, die dem Klick-Handler des Elements zugewiesen ist. Ist das tatsächlich der Fall?

Weil ich anfange, solche Dinge zu tun:

<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! --> 

Welches funktioniert. Aber ich weiß nicht, wie viel Hack das ist. Es sieht verdächtig aus, weil es keine offensichtliche Funktion gibt, von der zurückgegeben wird!

Sie könnten fragen, warum machen Sie das, Steve? Inline JS ist eine schlechte Praxis!

Um ganz ehrlich zu sein, habe ich es satt, drei verschiedene Codeabschnitte zu bearbeiten, um nur einen Abschnitt einer Seite zu ändern, insbesondere wenn ich nur Prototypen erstelle, um zu sehen, ob es überhaupt funktioniert. Es ist so viel einfacher und manchmal sogar sinnvoll, den Code, der sich speziell auf dieses HTML-Element bezieht, direkt im Element zu definieren : Wenn ich 2 Minuten später entscheide, dass dies eine schreckliche, schreckliche Idee war, kann ich das gesamte div (oder was auch immer) zerstören ) und ich habe keine Menge mysteriöser JS- und CSS-Cruft im Rest der Seite, die das Rendern etwas verlangsamen. Dies ähnelt dem Konzept der Referenzlokalität, aber anstelle von Cache-Fehlern betrachten wir Fehler und aufgeblähten Code.

Steven Lu
quelle
3
Sie haben Recht, es ist eine anonyme Funktion.
Bhamlin
1
Sie müssen die Abfrage für #click_medas DOMready-Ereignis verknüpfen oder das Skript nach dem Knoten platzieren.
Bergi
1
In einer Konsole tun document.getElementById("click_me").onclick;. Oder alarmieren Sie es. Sie werden sehen, dass es sich um eine Funktion handelt.
D. Strout

Antworten:

96

Sie haben es fast richtig verstanden, aber Sie haben den thisWert, der für den Inline-Code angegeben wurde, nicht berücksichtigt .

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

ist eigentlich näher an:

<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>

Inline-Ereignishandler this, die dem Ziel des Ereignisses entsprechen. Sie können die anonyme Funktion auch im Inline-Skript verwenden

<a href="#" onclick="(function(){alert(this);})()">Click Me</a>
Apsiller
quelle
7
Das Skript muss nach dem Tag stehen, sonst existiert das Tag nicht, wenn es ausgeführt wird. Ich schlage vor, Ihre Antwort zu ändern, um dies widerzuspiegeln.
undefiniert
Wie propagiere ich das eventmit einem Inline onclick='myFunction(event)'?
Oldboy
9

Was der Browser macht, wenn Sie haben

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

ist, den tatsächlichen Wert von "onclick" auf etwas effektiv zu setzen wie:

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

Das heißt, es wird eine Funktion erstellt, die einen "Ereignis" -Parameter erwartet. (Nun, IE nicht; es ist eher eine einfache anonyme Funktion.)

Spitze
quelle
2
Ah. Ich kann die Variable also tatsächlich verwenden event, um das Ereignis (und das Ursprungselement davon über event.target) aus meinem Inline-JS-Snippet abzurufen ! Cool.
Steven Lu
1
IE übergibt den eventParameter wirklich nicht , aber wenn Sie ihn eventinnerhalb dieser anonymen Funktion verwenden, versteht IE ihn als das eigentliche Ereignisobjekt. Da die anonyme Funktion windowim IE als Eigenschaft eines Objekts festgelegt ist, wird dies als angezeigt window.event.
rdleal
8

Es scheint eine Menge schlechter Praktiken zu geben , die um Event-Handler-Attribute geworfen werden. Schlechte Praxis besteht darin, die verfügbaren Funktionen nicht zu kennen und dort zu verwenden, wo sie am besten geeignet sind. Die Ereignisattribute sind vollständig W3C-dokumentierte Standards und es gibt keine schlechten Praktiken. Es ist nicht anders als das Platzieren von Inline-Stilen, die ebenfalls W3C-dokumentiert sind und in bestimmten Zeiten nützlich sein können. Unabhängig davon, ob Sie es in Skript-Tags verpackt platzieren oder nicht, wird es auf die gleiche Weise interpretiert.

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

Daniel B.
quelle
2
Ja, ich bin geneigt zuzustimmen, und ich habe sogar vernünftige "Gründe" angegeben, warum diese besondere Art der Verwendung von Inline-Code in bestimmten Situationen gerechtfertigt sein könnte. Aber die Realität ist , dass , wenn eine App (Web - App oder auf andere Weise) wird eine gewisse Komplexität sein (und dies in der Regel nicht einmal sehr viel Zeit oder Arbeit zu erreichen nehmen) mit kleinen Schnipseln Code verstreut über das HTML - Layout ist wahrscheinlich aus Sicht der Wartbarkeit architektonisch nicht einwandfrei sein. Wenn man zum Beispiel sogar anfängt, JS direkt in einer HTML-Datei zu codieren, versucht man die rutschige Neigung der Spaghettifizierung.
Steven Lu
1
Und das ist ein richtiges Argument dagegen, dem ich zustimme. Normalerweise füge ich selbst kein Inline-Scripting oder Styling für diese Materie hinzu. Aber die Leute haben unterschiedliche Geschmäcker. Viele zum Beispiel fügen gerne Skript- und Stil-Tags in den Body-Bereich ein, ich kann es nicht ertragen. Aber es ist gültig und einige Leute mögen es. Was Nähte bad practice/spaghettificationfür einige mögen , ist good practice/structurefür andere.
Daniel B
Ich habe mir github.com/styled-components/styled-components angesehen und wenn Sie dies beispielsweise mit Reagieren kombinieren, haben wir jetzt alles, was mit einer Komponente Ihrer App verbunden ist, die tatsächlich (hoffentlich friedlich) an einem Ort zusammenlebt. Und es sieht auch nicht schrecklich aus. Fühlt sich nach Fortschritt an. In diesem Licht ist das Jammen von Inline-Stilen und Code in HTML nicht der richtige Weg (bisher scheint es das Jammen von HTML und Stilen in den JS-Code zu sein).
Steven Lu
5

Der beste Weg, um Ihre Frage zu beantworten, besteht darin , sie in Aktion zu sehen.

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

In der js

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

Wie Sie in sehen console, wird bei Verwendung von Chrome eine anonyme Funktion mit dem übergebenen Ereignisobjekt gedruckt, obwohl dies im IE etwas anders ist.

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

Ich stimme einigen Ihrer Punkte zu Inline-Event-Handlern zu. Ja, sie sind einfach zu schreiben, aber ich stimme Ihrem Standpunkt nicht zu, dass Sie Code an mehreren Stellen ändern müssen. Wenn Sie Ihren Code gut strukturieren, sollten Sie dies nicht tun müssen.

Aziz Punjani
quelle
Ich denke, so etwas <button onclick="login()"> test login </button>ist für das Prototyping vollkommen in Ordnung. Sie möchten etwas testen, das jetzt Benutzerinteraktion erfordert, und Sie werden es später sowieso nur löschen. Warum überall zusätzlichen Code schreiben?
Dagg Nabbit
Es ist kein zusätzlicher Code, sondern nur eine zusätzliche anonyme Funktion. Und es ist nicht überall, es ist eigentlich alles an einem Ort, in den Skript-Tags.
Aziz Punjani
Ich bin mir nicht sicher, ob wir die gleiche Idee haben, "Ihren Code gut zu strukturieren". Wenn Sie die Benutzeroberfläche an dem Ort an Ihre "Kernfunktionen" binden, an dem Ihre Kernfunktionen tatsächlich ausgeführt werden, scheint mir dies eine schlechtere Kopplungsanordnung zu sein, als sie nur in der Benutzeroberfläche zu binden. Normalerweise halte ich alle UI-Bindungsmaterialien von den Kernmaterialien getrennt, und ich habe das Gefühl, dass das OP auch ...
Kernsachen
3

Es sieht verdächtig aus, weil es keine offensichtliche Funktion gibt, von der zurückgegeben wird!

Es ist eine anonyme Funktion, die an das Klickereignis des Objekts angehängt wurde.

Warum machst du das, Steve?

Warum um alles in der Welt bist du doi ..... Ah vergiss es, wie du erwähnt hast, es ist wirklich eine weit verbreitete schlechte Praxis :)

mattytommo
quelle
3

Versuchen Sie dies in der Konsole:

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

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

div.onclick

In Chrome wird Folgendes angezeigt:

function onclick(event) {
  alert(event)
}

... und die nicht standardmäßige nameEigenschaft von div.onclickist"onclick" .

Ob dies anonym ist oder nicht, hängt von Ihrer Definition von "anonym" ab. Vergleichen Sie mit so etwas wie var foo = new Function(), wo foo.nameeine leere Zeichenfolge ist, und foo.toString()erzeugen Sie so etwas wie

function anonymous() {

}
Dagg Nabbit
quelle
Dies begann als Kommentar zu Pointys Antwort, funktionierte aber wirklich nicht als Kommentar. Seine Antwort ist hier wirklich die beste, denke ich.
Dagg Nabbit