Apakah elemen pohon DOM dengan id menjadi variabel global?

364

Bekerja pada ide untuk pembungkus HTMLElement sederhana, saya menemukan yang berikut untuk Internet Explorer dan Chrome :

Untuk HTMLElement dengan ID yang diberikan di pohon DOM, dimungkinkan untuk mengambil div menggunakan ID-nya sebagai nama variabel. Jadi untuk div seperti

<div id="example">some text</div>

di Internet Explorer 8 dan Chrome yang dapat Anda lakukan:

alert(example.innerHTML); //=> 'some text'

atau

alert(window['example'].innerHTML); //=> 'some text'

Jadi, apakah ini berarti setiap elemen di pohon DOM dikonversi ke variabel di namespace global? Dan apakah itu juga berarti seseorang dapat menggunakan ini sebagai pengganti getElementByIdmetode di browser ini?

KooiInc
sumber
6
Lihat juga. Mengapa kita tidak menggunakan ID elemen saja sebagai pengidentifikasi dalam JavaScript? tentang mengapa ini tidak boleh digunakan, dan Apakah ada spesifikasi bahwa id elemen dibuat variabel global? tentang bagaimana itu ditentukan.
Bergi
1
@Bergi, komentar yang menyatakan tidak melakukan ini sekarang sudah usang dan bahkan tidak valid. Karenanya, saya tidak dapat menemukan alasan konkret untuk tidak menggunakan fitur ini.
ESR
@ EdmundReed Anda mungkin ingin membaca jawaban dari pertanyaan terkait lagi - itu masih ide yang buruk: " variabel global yang dinyatakan secara implisit " tidak memiliki dukungan perkakas yang buruk dan " menyebabkan kode rapuh ". Jangan menyebutnya "fitur", jawaban di bawah ini menjelaskan bagaimana itu hanya bug yang menjadi bagian dari standar karena alasan kompatibilitas.
Bergi
1
@Bergi cukup adil, kau benar. Saya masih berpikir itu fitur yang sangat rapi, dan hanya dianggap bermasalah karena orang tidak menyadarinya. Ini adalah bagaimana saya membayangkan menggunakannya: codepen.io/esr360/pen/WEavGE?editors=1000#0
ESR
@ EdmundReed Tidak terlalu bermasalah jika Anda tidak memisahkan konten dan logika dengan benar. Saya juga merekomendasikan untuk tidak pernah menggunakan penangan acara inline atau menginstal metode khusus pada elemen DOM yang menyalahgunakan mereka sebagai ruang nama (perhatikan itu bukan "ruang lingkup").
Bergi

Jawaban:

395

Apa yang seharusnya terjadi adalah bahwa 'elemen bernama' ditambahkan sebagai sifat nyata dari documentobjek. Ini adalah ide yang sangat buruk, karena memungkinkan nama elemen untuk berbenturan dengan properti nyata document.

IE memperburuk situasi dengan menambahkan elemen bernama sebagai properti dari windowobjek. Ini sangat buruk karena sekarang Anda harus menghindari penamaan elemen setelah anggota documentatau windowobjek yang Anda (atau kode perpustakaan lain dalam proyek Anda) mungkin ingin gunakan.

Ini juga berarti bahwa elemen-elemen ini terlihat sebagai variabel seperti global. Untungnya dalam hal ini setiap global nyata varatau functiondeklarasi dalam kode Anda membayangi mereka, jadi Anda tidak perlu terlalu khawatir tentang penamaan di sini, tetapi jika Anda mencoba untuk melakukan tugas ke variabel global dengan nama bentrok dan Anda lupa untuk mendeklarasikan itu var, Anda akan mendapatkan kesalahan di IE saat mencoba untuk menetapkan nilai ke elemen itu sendiri.

Secara umum dianggap praktik buruk untuk dihilangkan var, serta bergantung pada unsur-unsur yang disebutkan terlihat windowatau sebagai global. Berpegang teguh pada document.getElementById, yang lebih banyak didukung dan kurang ambigu. Anda dapat menulis fungsi pembungkus sepele dengan nama yang lebih pendek jika Anda tidak suka mengetik. Either way, tidak ada gunanya menggunakan cache pencarian id-to-elemen, karena browser biasanya mengoptimalkan getElementByIdpanggilan untuk menggunakan pencarian cepat; yang Anda dapatkan adalah masalah saat elemen berubah idatau ditambahkan / dihapus dari dokumen.

Opera disalin IE, kemudian webkit bergabung, dan sekarang kedua praktek sebelumnya unstandardised menempatkan elemen bernama pada documentproperti, dan sebelumnya IE-satunya praktek menempatkan mereka pada windowyang sedang distandarisasi oleh HTML5, yang pendekatan adalah untuk mendokumentasikan dan membakukan setiap praktik buruk yang ditimpakan pada kami oleh penulis peramban, menjadikan mereka bagian dari web selamanya. Jadi Firefox 4 juga akan mendukung ini.

Apa itu 'elemen yang dinamai'? Apa pun dengan id, dan apa pun dengan nameyang digunakan untuk tujuan 'mengidentifikasi': yaitu, formulir, gambar, jangkar, dan beberapa lainnya, tetapi bukan contoh nameatribut yang tidak terkait lainnya , seperti nama kontrol di bidang input formulir, nama parameter di <param>atau ketik metadata di <meta>. 'Identifikasi' nameadalah yang harus dihindari dalam mendukung id.

bobince
sumber
5
Itu jawaban yang jelas, terima kasih. Bukan ide saya untuk menghilangkan document.getElementById (well, sebenarnya saya menggunakan xpath jika memungkinkan untuk mencari elemen / elemen properti saat ini). Saya menemukan praktik (buruk) untuk item bernama ini dan ingin tahu dari mana asalnya. Anda menjawabnya cukup banyak; sekarang kita tahu mengapa itu juga dapat ditemukan di Chrome (webkit).
KooiInc
18
Satu pengecualian untuk "penggunaan nameharus dihindari" adalah dengan <input>, di mana nameatribut memainkan peran penting dalam membentuk kunci pasangan nilai kunci untuk pengiriman formulir.
Yahel
7
FYI Firefox hanya melakukan ini ketika dimasukkan ke mode quirks.
Crescent Fresh
4
@yahelc: itulah perbedaan yang saya buat. “Bukan kegunaan lain dari namenama kontrol seperti di kolom input formulir ...”
bobince
13
MENGAPA!? Adakah yang bisa kita lakukan untuk menghentikan kegilaan ini? Fungsi saya didefinisikan ulang oleh referensi ke elemen dan butuh satu jam bagi saya untuk debug. :(
Farzher
52

Seperti disebutkan dalam jawaban sebelumnya perilaku ini dikenal sebagai akses bernama pada objek jendela . Nilai nameatribut untuk beberapa elemen dan nilai idatribut untuk semua elemen tersedia sebagai properti dari windowobjek global . Ini dikenal sebagai elemen bernama. Karena windowmerupakan objek global di browser, setiap elemen bernama akan dapat diakses sebagai variabel global.

Ini awalnya ditambahkan oleh Internet Explorer dan akhirnya diimplementasikan oleh semua browser lain hanya untuk kompatibilitas dengan situs yang bergantung pada perilaku ini. Menariknya, Gecko (mesin rendering Firefox) memilih untuk menerapkan ini dalam mode quirks saja, sedangkan mesin rendering lainnya membiarkannya dalam mode standar.

Namun, pada Firefox 14, Firefox sekarang mendukung akses bernama pada windowobjek dalam mode standar juga. Mengapa mereka mengubah ini? Ternyata masih banyak situs yang mengandalkan fungsi ini dalam mode standar. Microsoft bahkan merilis demo pemasaran yang berfungsi, mencegah demo bekerja di Firefox.

Webkit baru-baru ini mempertimbangkan sebaliknya , mengalihkan akses bernama pada windowobjek ke mode quirks saja. Mereka memutuskan untuk tidak melakukannya dengan alasan yang sama seperti Gecko.

Jadi ... gila sepertinya perilaku ini sekarang secara teknis aman untuk digunakan dalam versi terbaru dari semua browser utama dalam mode standar . Tetapi sementara akses yang diberi nama bisa terasa nyaman, seharusnya tidak digunakan .

Mengapa? Banyak alasan yang dapat dirangkum dalam artikel ini tentang mengapa variabel global buruk . Sederhananya, memiliki banyak variabel global tambahan mengarah ke lebih banyak bug. Katakanlah Anda tidak sengaja mengetik nama vardan kebetulan mengetikkan idsimpul DOM, KEJUTAN!

Selain itu, meskipun telah distandarisasi, masih ada beberapa perbedaan dalam implementasi akses bernama browser.

  • IE salah membuat nilai nameatribut dapat diakses untuk elemen form (input, pilih, dll).
  • Gecko dan Webkit salah JANGAN membuat <a>tag dapat diakses melalui nameatributnya.
  • Gecko secara tidak benar menangani banyak elemen bernama dengan nama yang sama (ia mengembalikan referensi ke satu simpul alih-alih susunan referensi).

Dan saya yakin masih ada lagi jika Anda mencoba menggunakan akses bernama pada kasus tepi.

Seperti disebutkan dalam jawaban lain gunakan document.getElementByIduntuk mendapatkan referensi ke simpul DOM dengan nya id. Jika Anda perlu mendapatkan referensi ke sebuah simpul dengan namemenggunakan atributnya document.querySelectorAll.

Tolong, tolong jangan menyebarkan masalah ini dengan menggunakan akses bernama di situs Anda. Begitu banyak pengembang web yang menyia-nyiakan waktu untuk melacak perilaku ajaib ini . Kita benar-benar perlu mengambil tindakan dan membuat mesin rendering untuk mematikan akses bernama dalam mode standar. Dalam jangka pendek itu akan merusak beberapa situs melakukan hal-hal buruk, tetapi dalam jangka panjang itu akan membantu memajukan web.

Jika Anda tertarik saya membicarakan hal ini lebih detail di blog saya - https://www.tjvantoll.com/2012/07/19/dom-element-references-as-global-variables/ .

TJ VanToll
sumber
3
Hanya catatan untuk peringatan yang jelas untuk premis bahwa "itu tidak boleh digunakan". Artinya, "itu tidak boleh digunakan KECUALI Anda kebetulan seorang koboi kode." Kode koboi lakukan saja.
Jeremy Foster
5
@jeremyfoster kecuali "kode koboi" berarti seseorang yang menggunakan dan menyebarkan implementasi pengembang yang tidak ramah, saya sangat tidak setuju.
Patrick Roberts
2
Satu tanda koboi yang baik adalah banyak yang tidak setuju. Tapi sekarang saya seperti koboi filosofis atau sesuatu seperti itu.
Jeremy Foster
Lebih banyak orang harus menggunakan document.querySelectorAlldan document.querySelectorketika mengakses DOM. +1 untuk saran yang baik untuk menggunakannya. Mengakses elemen oleh pemilih jelas merupakan proses yang lebih efisien.
Travis J
20

Anda harus berpegang teguh getElementById()pada kasus-kasus ini, misalnya:

document.getElementById('example').innerHTML

IE suka mencampur elemen-elemen dengan name dan ID atribut - atribut di namespace global, jadi lebih baik untuk secara eksplisit tentang apa yang Anda coba dapatkan.

Nick Craver
sumber
3

Ya mereka melakukanya.

Diuji di Chrome 55, Firefox 50, IE 11, IE Edge 14, dan Safari 10
dengan contoh berikut:

<!DOCTYPE html>
<html>
<head>
</head>
<body>
  <div id="im_not_particularly_happy_with_that">
    Hello World!
  </div>
  <script>
    im_not_particularly_happy_with_that.innerText = 'Hello Internet!';
  </script>
  <!-- Looking at you W3 HTML5 spec group _ -->
</body>
</html>

http://jsbin.com/mahobinopa/edit?html,output

qff
sumber
1
Juga di Opera. Namun, saya pikir keberatan terhadap mekanisme yang diungkapkan pada halaman ini diambil dengan sangat baik.
ncmathsadist
1

Pertanyaannya harus berbunyi :: "Apakah Tag HTML dengan ID yang disediakan menjadi DOM Elements yang dapat diakses secara global?"

Jawabannya iya!

Begitulah cara itu dimaksudkan untuk bekerja, dan itulah sebabnya ID diperkenalkan oleh W3C untuk memulai dengan .: ID dari Tag HTML dalam lingkungan skrip yang diuraikan menjadi pegangan Elemen DOM yang sesuai.

Namun, Netscape Mozilla menolak untuk menyesuaikan diri (dengan mereka mengganggu) W3C dan dengan keras kepala tetap menggunakan atribut Nama yang sudah usang untuk membuat kekacauan dan karena itu memecah fungsionalitas Scripting dan kenyamanan pengkodean yang dibawa oleh pengenalan unik ID W3C.

Setelah kegagalan Netscape Navigator 4.7, pengembang mereka semua pergi dan menyusup ke W3C, sedangkan rekan mereka menggantikan Web dengan praktik yang salah dan contoh yang salah. Memaksa penggunaan dan penggunaan kembali atribut Name yang sudah usang [! Yang tidak dimaksudkan untuk menjadi unik] setara dengan atribut ID sehingga skrip yang menggunakan ID menangani untuk mengakses elemen DOM tertentu akan dengan mudah putus!

Dan istirahat mereka lakukan karena mereka juga akan menulis dan menerbitkan pelajaran dan contoh pengkodean yang luas [browser mereka tidak akan mengenali pula] seperti document.all.ElementID.propertybukannya ElementID.propertysetidaknya membuatnya tidak efisien dan memberikan browser lebih banyak biaya jika itu tidak hanya memecahkannya di Domain HTML dengan menggunakan token yang sama untuk Nama (sekarang [1996-97], usang) dan atribut ID standar menyediakannya dengan nilai token yang sama.

Mereka dengan mudah berhasil meyakinkan - saat itu - pasukan amatir amatir yang menulis kode yang bodoh bahwa Nama dan ID praktis sama, kecuali bahwa atribut ID lebih pendek dan karena itu menghemat byte dan lebih nyaman untuk kode daripada properti Nama kuno. Yang tentu saja bohong. Atau - dalam menggantikan artikel HTML yang diterbitkan, artikel meyakinkan bahwa Anda harus memberikan Nama dan ID pada tag Anda agar dapat diakses oleh mesin Scripting.

Mosaic Killers [nama sandi "Mozilla"] sangat kesal mereka berpikir "jika kita turun, begitu juga Internet".

Microsoft yang sedang naik daun - di sisi lain - begitu naif sehingga mereka berpikir mereka harus menjaga properti usang dan ditandai untuk dihapus Nama dan memperlakukannya seolah-olah itu adalah ID yang merupakan Identifier unik sehingga mereka tidak akan merusak fungsi scripting dari halaman lama yang dikodekan oleh trainee Netscape. Mereka salah besar ...

Dan kembalinya koleksi array elemen yang bertentangan juga bukan solusi untuk masalah buatan manusia ini. Sebenarnya itu mengalahkan seluruh tujuan.

Dan ini adalah satu-satunya alasan W3C berubah jelek dan memberi kami kebodohan seperti document.getElementByIddan sintaks yang menyebalkan dari rococo sialan ... (...)

Bekim Bacaj
sumber