Jak działa wbudowany JavaScript (w HTML)?


130

Wiem, że to zła praktyka. Jeśli to możliwe, nie pisz takiego kodu.

Oczywiście zawsze znajdziemy się w sytuacjach, w których sprytny fragment wbudowanego kodu JavaScript może szybko rozwiązać problem.

Podążam za tym pytaniem, aby w pełni zrozumieć, co się dzieje (i potencjalne pułapki), gdy napisane jest coś takiego:

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

O ile wiem, funkcjonalnie jest to to samo, co

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

Ekstrapolując z tego, wydaje się, że ciąg przypisany do atrybutu onclickjest wstawiany w anonimowej funkcji, która jest przypisana do modułu obsługi kliknięcia elementu. Czy tak jest w rzeczywistości?

Ponieważ zaczynam robić takie rzeczy:

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

Co działa. Ale nie wiem, ile to hack. Wygląda podejrzanie, ponieważ nie ma żadnej funkcji, która jest zwracana!

Możesz zapytać, dlaczego to robisz, Steve? Inline JS to zła praktyka!

Cóż, jeśli mam być całkiem szczery, mam dość edytowania trzech różnych sekcji kodu tylko po to, aby zmodyfikować jedną sekcję strony, zwłaszcza gdy tylko prototypuję coś, aby zobaczyć, czy w ogóle zadziała. Jest to o wiele łatwiejsze, a czasem nawet ma sens, aby kod konkretnie powiązany z tym elementem HTML był zdefiniowany bezpośrednio w elemencie: Kiedy 2 minuty później zdecyduję, że to był okropny, okropny pomysł, mogę niszczyć cały div (lub cokolwiek innego ) i nie mam wielu tajemniczych okruchów JS i CSS w reszcie strony, spowalniających renderowanie nawet nieznacznie. Jest to podobne do koncepcji lokalizacji odniesienia, ale zamiast braków w pamięci podręcznej patrzymy na błędy i nadmiar kodu.


3
Masz rację, to funkcja anonimowa.
bhamlin

1
Będziesz musiał podłączyć zapytanie do #click_mezdarzenia DOMready lub umieścić skrypt za węzłem.
Bergi

1
Zrób to w konsoli document.getElementById("click_me").onclick;. Albo powiadom go. Zobaczysz, że jest to funkcja.
D. Strout

Odpowiedzi:


97

Masz prawie poprawne, ale nie uwzględniłeś thiswartości dostarczonej do kodu wbudowanego.

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

jest właściwie bliżej:

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

Wbudowane programy obsługi zdarzeń ustawione thisna wartość docelową zdarzenia. Możesz także użyć funkcji anonimowej w skrypcie wbudowanym

<a href="#" onclick="(function(){alert(this);})()">Click Me</a>

7
Skrypt musi znajdować się po tagu, w przeciwnym razie tag nie istnieje, gdy jest wykonywany - sugeruję zmianę odpowiedzi, aby to odzwierciedlić.
nieokreślony

jak propagować eventza pomocą inline onclick='myFunction(event)'?
oldboy

9

Co robi przeglądarka, gdy masz

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

to ustawienie rzeczywistej wartości „onclick” na coś podobnego do:

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

Oznacza to, że tworzy funkcję, która oczekuje parametru „zdarzenia”. (Cóż, IE tego nie robi; bardziej przypomina zwykłą, prostą funkcję anonimową).


2
Ach. Więc mogę faktycznie użyć zmiennej eventdo pobrania zdarzenia (i jego elementu źródłowego za pośrednictwem event.target) z mojego wbudowanego fragmentu kodu JS! Fajne.
Steven Lu

1
IE naprawdę nie przekazuje eventparametru, ale jeśli użyjesz eventwewnątrz tej anonimowej funkcji, IE zrozumie ją jako rzeczywisty obiekt zdarzenia. Ponieważ funkcja anonimowa jest ustawiona jako właściwość windowobiektu w IE, zobaczy to jako window.event.
rdleal

8

Wydaje się, że wokół atrybutów obsługi zdarzeń rzuca się dużo złych praktyk . Zła praktyka to nieznajomość i nieznajomość dostępnych funkcji tam, gdzie jest to najbardziej odpowiednie. Atrybuty zdarzeń są w pełni udokumentowanymi standardami W3C i nie ma w nich nic złego. Nie różni się to niczym od umieszczania stylów wbudowanych, co jest również udokumentowane w W3C i może być przydatne w czasach. Niezależnie od tego, czy umieścisz go w znacznikach skryptu, czy nie, będzie to interpretowane w ten sam sposób.

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


2
Tak, jestem skłonny się zgodzić i podałem nawet rozsądne „powody”, dla których ten szczególny rodzaj użycia wbudowanego kodu może być uzasadniony w pewnych sytuacjach. Ale rzeczywistość jest taka, że ​​gdy aplikacja (aplikacja internetowa lub inna) staje się bardziej złożona (a to zwykle nie zajmuje dużo czasu lub pracy), posiadanie niewielkich fragmentów kodu rozrzuconych na temat układu HTML prawdopodobnie być architektonicznie niezdrowe z punktu widzenia możliwości konserwacji. Nawet zaczynając na przykład bezpośrednio kodować JS w pliku HTML, kusi się śliskim zboczem spaghetti.
Steven Lu

1
I to jest właściwy argument przeciwko, z którym się zgadzam. Zwykle sam nie dodaję wbudowanych skryptów ani stylów dla tego materiału. Ale ludzie mają różne gusta. Wielu, na przykład, lubi dodawać tagi skryptu i stylu w sekcji treści, nie mogę tego znieść. Ale jest ważny i niektórym się to podoba. To, co szwy lubią bad practice/spaghettificationdla jednych, good practice/structuredla innych jest.
Daniel B

Patrzyłem na github.com/styled-components/styled-components i jeśli połączysz to na przykład z reakcją , mamy teraz wszystko, co jest związane z komponentem Twojej aplikacji, które faktycznie mieszkają razem (miejmy nadzieję, że spokojnie) w jednym miejscu. I faktycznie nie wygląda to strasznie. Czuje się jak postęp. W tym świetle zagłuszanie wbudowanych stylów i kodu do HTML nie jest właściwym sposobem (jak dotąd wydaje się, że jest to wbijanie HTML i stylów w kod JS).
Steven Lu

5

Najlepszym sposobem odpowiedzi na pytanie jest zobaczenie go w akcji.

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

W js

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

Jak widać w console, jeśli używasz chrome, wyświetla anonimową funkcję z przekazanym obiektem zdarzenia, chociaż w IE jest to trochę inne.

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

Zgadzam się z niektórymi twoimi uwagami na temat wbudowanych programów obsługi zdarzeń. Tak, są łatwe do napisania, ale nie zgadzam się z twoim punktem widzenia konieczności zmiany kodu w wielu miejscach, jeśli dobrze ustrukturyzujesz kod, nie powinieneś tego robić.


Myślę, że coś takiego <button onclick="login()"> test login </button>jest idealne do prototypowania. Chcesz przetestować coś, co wymaga interakcji użytkownika w tej chwili, i tak i tak zamierzasz usunąć to później. Po co pisać dodatkowy kod w każdym miejscu?
Dagg Nabbit

To nie jest dodatkowy kod, tylko dodatkowa funkcja anonimowa. I to nie jest wszędzie, tak naprawdę wszystko jest w jednym miejscu, w tagach skryptu.
aziz punjani

Nie jestem pewien, czy podzielamy ten sam pomysł na „dobrą strukturę kodu”. Jeśli połączysz interfejs użytkownika ze swoimi „podstawowymi funkcjami” w miejscu, w którym faktycznie działają twoje podstawowe funkcje, wydaje mi się, że jest to gorszy układ sprzężenia niż zwykłe powiązanie ich w interfejsie użytkownika. Zwykle trzymam wszystkie elementy związane z interfejsem użytkownika oddzielnie od podstawowych rzeczy i mam wrażenie, że OP może również ...
Dagg Nabbit

3

Wygląda podejrzanie, ponieważ nie ma żadnej funkcji, która jest zwracana!

Jest to anonimowa funkcja, która została dołączona do zdarzenia kliknięcia obiektu.

dlaczego to robisz, Steve?

Dlaczego doi ..... Ach nieważne, jak wspomniałeś, jest to naprawdę powszechnie przyjęta zła praktyka :)


3

Spróbuj tego w konsoli:

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

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

div.onclick

W Chrome pokazuje to:

function onclick(event) {
  alert(event)
}

... i niestandardowa namewłaściwość div.onclickis "onclick".

Zatem to, czy jest to anonimowe, zależy od definicji pojęcia „anonimowy”. Porównaj z czymś w rodzaju var foo = new Function(), gdzie foo.namejest pustym łańcuchem, a foo.toString()wygeneruje coś podobnego

function anonymous() {

}

Zaczęło się od komentarza do odpowiedzi Pointy, ale tak naprawdę nie działało jako komentarz. Myślę, że to naprawdę najlepsza odpowiedź.
Dagg Nabbit
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.