Bagaimana cara kerja inline Javascript (dalam HTML)?

129

Saya tahu ini adalah praktik buruk. Jangan menulis kode seperti ini jika memungkinkan.

Tentu saja, kita akan selalu menemukan diri kita dalam situasi di mana potongan pintar Javascript inline dapat mengatasi masalah dengan cepat.

Saya mengejar pertanyaan ini untuk memahami sepenuhnya apa yang terjadi (dan potensi jebakan) ketika sesuatu seperti ini ditulis:

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

Sejauh yang saya tahu ini secara fungsional sama dengan

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

Ekstrapolasi dari ini nampaknya bahwa string yang ditugaskan untuk atribut onclickdimasukkan dalam fungsi anonim yang ditugaskan untuk penangan klik elemen. Apakah ini yang sebenarnya terjadi?

Karena saya mulai melakukan hal-hal seperti ini:

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

Yang bekerja Tapi saya tidak tahu seberapa banyak retasan ini. Ini terlihat mencurigakan karena tidak ada fungsi jelas yang sedang dikembalikan!

Anda mungkin bertanya, mengapa Anda melakukan ini, Steve? Inline JS adalah praktik buruk!

Ya jujur ​​saja, saya bosan mengedit tiga bagian kode yang berbeda hanya untuk memodifikasi satu bagian halaman, terutama ketika saya hanya membuat prototipe sesuatu untuk melihat apakah itu akan bekerja sama sekali. Ini jauh lebih mudah dan kadang-kadang bahkan masuk akal untuk kode yang secara khusus terkait dengan elemen HTML ini untuk didefinisikan tepat di dalam elemen: Ketika saya memutuskan 2 menit kemudian bahwa ini adalah ide yang mengerikan, mengerikan saya bisa memuntahkan seluruh div (atau apa pun ) dan saya tidak memiliki banyak JS misterius dan cruft berkeliaran di sisa halaman, memperlambat rendering sedikit. Ini mirip dengan konsep lokalitas referensi tetapi alih-alih meleset dari cache, kami melihat bug dan mengasapi kode.

Steven Lu
sumber
3
Anda benar, ini adalah fungsi anonim.
bhamlin
1
Anda harus mengaitkan kueri untuk #click_meacara DOMready, atau menempatkan skrip setelah node.
Bergi
1
Di konsol, lakukan document.getElementById("click_me").onclick;. Atau beri tahu. Anda akan melihat bahwa itu ada dalam suatu fungsi.
D. Strout

Jawaban:

96

Anda sudah hampir benar, tetapi Anda belum memperhitungkan thisnilai yang diberikan ke kode sebaris.

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

sebenarnya lebih dekat ke:

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

Penangan acara sebaris yang disetel thissama dengan target acara. Anda juga dapat menggunakan fungsi anonim dalam skrip inline

<a href="#" onclick="(function(){alert(this);})()">Click Me</a>
apsillers
sumber
7
Script harus muncul setelah tag, jika tidak tag tidak ada ketika dieksekusi - saya sarankan mengubah jawaban Anda untuk mencerminkan ini.
undefined
bagaimana cara menyebarkan eventdengan inline onclick='myFunction(event)'??
oldboy
9

Apa yang dilakukan browser saat Anda memilikinya

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

adalah mengatur nilai aktual "onclick" menjadi sesuatu yang efektif seperti:

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

Yaitu, ia menciptakan fungsi yang mengharapkan parameter "event". (Ya, IE tidak; itu lebih seperti fungsi anonim sederhana sederhana.)

Runcing
sumber
2
Ah. Jadi saya benar-benar dapat menggunakan variabel eventuntuk mengambil acara (dan elemen yang berasal dari via event.target), dari potongan JS inline saya! Keren.
Steven Lu
1
IE benar-benar tidak lulus eventparameter, tetapi jika Anda menggunakan eventdi dalam fungsi anonim ini IE akan memahaminya sebagai Objek Acara yang sebenarnya. Karena fungsi anonim ditetapkan sebagai properti windowobjek di IE, ia akan melihat ini sebagai window.event.
rdleal
8

Tampaknya ada banyak praktik buruk yang dilemparkan ke Atribut Event Handler. Praktik buruk adalah tidak mengetahui dan menggunakan fitur yang tersedia di tempat yang paling tepat. Atribut Acara sepenuhnya standar W3C yang didokumentasikan dan tidak ada praktik buruk tentang mereka. Ini tidak berbeda dengan menempatkan gaya inline, yang juga didokumentasikan W3C dan dapat berguna pada saatnya. Apakah Anda menempatkannya dalam tag skrip atau tidak, itu akan ditafsirkan dengan cara yang sama.

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

Daniel B
sumber
2
Ya saya cenderung setuju, dan saya bahkan memberikan "alasan" yang masuk akal mengapa penggunaan kode inline semacam ini dapat dibenarkan dalam situasi tertentu. Tetapi kenyataannya adalah bahwa ketika suatu aplikasi (aplikasi web atau lainnya) menjadi suatu kompleksitas tertentu (dan ini bahkan biasanya tidak memerlukan banyak waktu atau pekerjaan untuk mencapai) memiliki sedikit potongan kode yang berserakan tentang tata letak HTML cenderung secara arsitektur tidak sehat dari perspektif rawatan. Dengan bahkan mulai secara langsung kode JS dalam file HTML, misalnya, seseorang menggoda lereng licin spaghettification.
Steven Lu
1
Dan itu adalah argumen yang sah yang menentang, yang saya setujui. Saya biasanya tidak menambahkan skrip inline, atau gaya untuk mater itu sendiri. Tetapi orang-orang memiliki selera yang berbeda. Banyak misalnya ingin menambahkan skrip dan tag gaya di bagian tubuh, saya tidak tahan. Tetapi ini valid dan sebagian orang menyukainya. Apa yang jahitan bad practice/spaghettificationbagi sebagian orang, good practice/structurebagi orang lain.
Daniel B
Saya telah melihat github.com/styled-components/styled-components dan jika Anda menggabungkan ini dengan reaksi, misalnya, kami sekarang memiliki semua yang terkait dengan komponen aplikasi Anda yang benar-benar hidup bersama (semoga damai) di satu tempat. Dan itu sebenarnya tidak terlihat buruk juga. Terasa seperti kemajuan. Dalam hal ini, kemacetan gaya inline dan kode ke dalam HTML bukanlah cara yang benar (sejauh ini tampaknya menjadi kemacetan HTML dan gaya ke dalam kode JS).
Steven Lu
5

Cara terbaik untuk menjawab pertanyaan Anda adalah melihatnya dalam tindakan.

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

Di js

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

Seperti yang Anda lihat di console, jika Anda menggunakan chrome, ia mencetak fungsi anonim dengan objek acara dilewatkan, meskipun sedikit berbeda di IE.

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

Saya setuju dengan beberapa poin Anda tentang penangan event inline. Ya mereka mudah untuk ditulis, tetapi saya tidak setuju dengan poin Anda tentang harus mengubah kode di banyak tempat, jika Anda menyusun kode dengan baik, Anda tidak perlu melakukan ini.

aziz punjani
sumber
Saya pikir sesuatu seperti <button onclick="login()"> test login </button>itu baik-baik saja untuk membuat prototipe. Anda ingin menguji sesuatu yang memerlukan interaksi pengguna sekarang, dan Anda hanya akan menghapusnya nanti. Mengapa menulis kode tambahan di semua tempat?
Dagg Nabbit
Ini bukan kode tambahan, hanya fungsi anonim tambahan. Dan itu tidak semua tempat, itu sebenarnya semua di satu tempat, di tag skrip.
aziz punjani
Saya tidak yakin kami memiliki gagasan yang sama tentang "menyusun kode dengan baik." Jika Anda mengikat UI ke "fungsi inti" Anda di tempat di mana fungsi inti Anda benar-benar hidup, ini bagi saya sepertinya pengaturan sambungan yang lebih buruk daripada hanya mengikatnya di UI. Saya biasanya menjaga semua hal yang mengikat UI terpisah dari hal-hal inti, dan saya merasa OP mungkin juga ...
Dagg Nabbit
3

Ini terlihat mencurigakan karena tidak ada fungsi jelas yang sedang dikembalikan!

Ini adalah fungsi anonim yang telah dilampirkan ke acara klik objek.

kenapa kamu melakukan ini, Steve?

Mengapa kamu melakukan ... Ah tidak pernah, seperti yang telah Anda sebutkan, itu benar-benar praktik buruk yang diadopsi secara luas :)

mattytommo
sumber
3

Coba ini di konsol:

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

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

div.onclick

Di Chrome, ini menunjukkan ini:

function onclick(event) {
  alert(event)
}

... dan non-standar namemilik div.onclickyaitu "onclick".

Jadi, apakah ini anonim atau tidak tergantung definisi Anda tentang "anonim." Bandingkan dengan sesuatu seperti var foo = new Function(), di mana foo.namestring kosong, dan foo.toString()akan menghasilkan sesuatu seperti

function anonymous() {

}
Dagg Nabbit
sumber
Ini dimulai sebagai komentar pada jawaban Pointy, tetapi benar-benar tidak berfungsi sebagai komentar. Dia benar-benar jawaban terbaik di sini, saya kira.
Dagg Nabbit