องค์ประกอบ DOM ต้นไม้ที่มีรหัสกลายเป็นตัวแปรทั่วโลกหรือไม่


364

ทำงานกับแนวคิดของ wrapper HTMLElement อย่างง่ายฉันสะดุดกับสิ่งต่อไปนี้สำหรับ Internet Explorer และChrome :

สำหรับ HTMLElement ที่มี ID ในทรี DOM เป็นไปได้ที่จะดึง div โดยใช้ ID เป็นชื่อตัวแปร ดังนั้นสำหรับ div เช่น

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

ในInternet Explorer 8และ Chrome คุณสามารถทำได้:

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

หรือ

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

ดังนั้นนี่หมายความว่าทุกองค์ประกอบในทรี DOMถูกแปลงเป็นตัวแปรในเนมสเปซส่วนกลางหรือไม่ และยังหมายความว่าเราสามารถใช้สิ่งนี้แทนgetElementByIdวิธีการในเบราว์เซอร์เหล่านี้ได้หรือไม่?



1
@Bergi ความคิดเห็นที่ระบุว่าจะไม่ทำเช่นนี้ในขณะนี้ล้าสมัยและไม่ถูกต้อง ดังนั้นฉันไม่พบเหตุผลที่ชัดเจนที่จะไม่ใช้คุณสมบัตินี้
ESR

@EdmundReed คุณอาจต้องการอ่านคำตอบของคำถามที่เชื่อมโยงอีกครั้ง - มันยังเป็นความคิดที่ดี: " ตัวแปรทั่วโลกที่ประกาศโดยปริยาย " ไม่มีประโยชน์ในการสนับสนุนเครื่องมือและ " นำไปสู่รหัสที่เปราะ " อย่าเรียกมันว่า "ฟีเจอร์" คำตอบด้านล่างอธิบายว่ามันเป็นเพียงข้อบกพร่องที่กลายเป็นส่วนหนึ่งของมาตรฐานด้วยเหตุผลด้านความเข้ากันได้
Bergi

1
@Bergi ยุติธรรมเพียงพอคุณพูดถูก ฉันยังคงคิดว่ามันเป็นคุณสมบัติที่ประณีตมาก ๆ และถือว่าเป็นปัญหาเพราะคนไม่ได้ตระหนักถึงมัน นี่คือวิธีที่ฉันจินตนาการถึงการใช้งานมัน: codepen.io/esr360/pen/WEavGE?editors=1000#0
ESR

@EdmundReed มันมีปัญหาน้อยกว่าถ้าคุณแยกเนื้อหาและตรรกะออกจากกันอย่างไม่เหมาะสม นอกจากนี้ฉันขอแนะนำว่าอย่าใช้เครื่องมือจัดการเหตุการณ์แบบอินไลน์หรือติดตั้งวิธีการที่กำหนดเองในองค์ประกอบ DOM ที่ใช้งานพวกเขาเป็นเนมสเปซ (โปรดสังเกตว่าไม่ใช่ "ขอบเขต")
Bergi

คำตอบ:


395

สิ่งที่ควรเกิดขึ้นคือมีการเพิ่ม 'องค์ประกอบที่มีชื่อ' เป็นคุณสมบัติที่ชัดเจนของdocumentวัตถุ documentนี้เป็นความคิดที่ไม่ดีจริงๆมันช่วยให้ชื่อองค์ประกอบที่จะปะทะกับคุณสมบัติที่แท้จริงของ

IE ทำให้สถานการณ์แย่ลงด้วยการเพิ่มองค์ประกอบที่มีชื่อเป็นคุณสมบัติของwindowวัตถุ นี้จะไม่ดีทวีคูณในการที่ตอนนี้คุณต้องหลีกเลี่ยงการตั้งชื่อองค์ประกอบของคุณหลังจากที่สมาชิกของทั้งใด ๆdocumentหรือwindowวัตถุที่คุณ (หรือรหัสห้องสมุดอื่น ๆ ในโครงการของคุณ) อาจต้องการที่จะใช้

นอกจากนี้ยังหมายความว่าองค์ประกอบเหล่านี้สามารถมองเห็นได้เป็นตัวแปรที่เหมือนทั่วโลก โชคดีในกรณีนี้จริง ๆ ทั่วโลกvarหรือfunctionการประกาศในรหัสของคุณเงาพวกเขาดังนั้นคุณไม่จำเป็นต้องกังวลมากเกี่ยวกับการตั้งชื่อที่นี่ แต่ถ้าคุณพยายามที่จะมอบหมายให้ตัวแปรทั่วโลกที่มีชื่อปะทะกันและคุณลืมที่จะประกาศ มันvarคุณจะได้รับข้อผิดพลาดใน IE ในขณะที่มันพยายามที่จะกำหนดค่าเป็นองค์ประกอบของตัวเอง

โดยทั่วไปถือว่าเป็นการปฏิบัติที่ไม่ดีที่จะละเว้นvarเช่นเดียวกับการพึ่งพาองค์ประกอบที่มีชื่อซึ่งมองเห็นได้บนwindowหรือเป็นกลม ติดไปdocument.getElementByIdซึ่งได้รับการสนับสนุนอย่างกว้างขวางมากขึ้นและคลุมเครือน้อยลง คุณสามารถเขียนฟังก์ชั่น wrapper เล็กน้อยด้วยชื่อที่สั้นกว่าหากคุณไม่ชอบการพิมพ์ ไม่ว่าจะด้วยวิธีใดก็ตามไม่มีจุดในการใช้แคชการค้นหา id-to-element เพราะเบราว์เซอร์มักจะปรับการgetElementByIdเรียกให้ใช้การค้นหาอย่างรวดเร็วอย่างไรก็ตาม สิ่งที่คุณได้รับคือปัญหาเมื่อองค์ประกอบเปลี่ยนidหรือถูกเพิ่ม / ลบออกจากเอกสาร

Opera คัดลอก IE แล้ว WebKit เข้าร่วมและตอนนี้ทั้งสองวิธีปฏิบัติที่ไม่ได้มาตรฐานก่อนหน้านี้ของการใส่องค์ประกอบที่มีชื่อในdocumentคุณสมบัติและการปฏิบัติก่อนหน้านี้ IE เท่านั้นอย่างเดียวของการวางพวกเขาwindowจะถูก มาตรฐานโดย HTML5 ซึ่งแนวทางคือเอกสารและมาตรฐาน การปฏิบัติที่น่าสยดสยองกับเราโดยผู้เขียนเบราว์เซอร์ทำให้พวกเขาเป็นส่วนหนึ่งของเว็บตลอดไป ดังนั้น Firefox 4 จะสนับสนุนสิ่งนี้ด้วย

'องค์ประกอบที่มีชื่อ' คืออะไร สิ่งใด ๆ ที่มีidและสิ่งใดก็ตามที่มีnameการใช้เพื่อวัตถุประสงค์ 'ระบุ': นั่นคือรูปแบบรูปภาพจุดยึดและอีกสองสามอย่าง แต่ไม่ใช่อินสแตนซ์ที่ไม่เกี่ยวข้องอื่น ๆ ของnameแอตทริบิวต์เช่นชื่อควบคุมในฟิลด์อินพุตแบบฟอร์มชื่อพารามิเตอร์ในหรือเมตาดาต้าพิมพ์ใน<param> <meta>'ระบุ' names idเป็นคนที่ควรควรหลีกเลี่ยงในความโปรดปรานของ


5
นั่นเป็นคำตอบที่ชัดเจนขอบคุณ มันไม่ใช่ความคิดของฉันที่จะละเว้น document.getElementById (ที่จริงฉันใช้ xpath ที่เป็นไปได้ในการค้นหาองค์ประกอบ / องค์ประกอบคุณสมบัติในปัจจุบัน) ฉันสะดุดกับการปฏิบัติที่ไม่ดีสำหรับรายการที่มีชื่อและอยากรู้ว่ามันมาจากไหน คุณตอบว่าพอเถอะ ตอนนี้เรารู้แล้วว่าทำไมจึงพบได้ใน Chrome (webkit)
KooiInc

18
มีข้อยกเว้นอย่างหนึ่งสำหรับ " nameควรหลีกเลี่ยงการใช้" ด้วย<input>โดยที่nameแอตทริบิวต์มีบทบาทสำคัญในการสร้างคีย์ของคู่คีย์ - ค่าสำหรับการส่งแบบฟอร์ม
Yahel

7
FYI Firefox ทำสิ่งนี้เมื่ออยู่ในโหมด quirks
Crescent Fresh

4
@ yahelc: นั่นคือความแตกต่างที่ฉันทำ “ ไม่ใช่การใช้nameชื่อควบคุมอื่นในฟิลด์ป้อนแบบฟอร์ม ... ”
bobince

13
ทำไม!? มีอะไรที่เราสามารถทำได้เพื่อหยุดความบ้าคลั่งนี้หรือไม่? ฟังก์ชั่นของฉันได้รับการนิยามใหม่โดยอ้างอิงถึงองค์ประกอบและใช้เวลาหนึ่งชั่วโมงในการดีบัก :(
Farzher

52

ตามที่ระบุไว้ในคำตอบก่อนหน้านี้พฤติกรรมนี้เป็นที่รู้จักกันเข้าถึงชื่อบนวัตถุหน้าต่าง ค่าของnameแอตทริบิวต์สำหรับองค์ประกอบบางอย่างและค่าของidแอตทริบิวต์สำหรับองค์ประกอบทั้งหมดจะพร้อมใช้งานเป็นคุณสมบัติของwindowวัตถุส่วนกลาง สิ่งเหล่านี้เรียกว่าองค์ประกอบที่มีชื่อ เนื่องจากwindowเป็นวัตถุส่วนกลางในเบราว์เซอร์องค์ประกอบที่มีชื่อแต่ละรายการจะสามารถเข้าถึงได้เป็นตัวแปรส่วนกลาง

เดิมนี้ถูกเพิ่มโดย Internet Explorer และในที่สุดก็มีการใช้งานโดยเบราว์เซอร์อื่น ๆ ทั้งหมดเพื่อความเข้ากันได้กับเว็บไซต์ที่ขึ้นอยู่กับพฤติกรรมนี้ น่าสนใจ Gecko (เอ็นจิ้นการเรนเดอร์ของ Firefox) เลือกใช้สิ่งนี้ในโหมด quirksเท่านั้นในขณะที่เอ็นจิ้นการเรนเดอร์อื่น ๆ ปล่อยมันไว้ในโหมดมาตรฐาน

อย่างไรก็ตามในฐานะของ Firefox 14 ตอนนี้ Firefox รองรับการเข้าถึงแบบมีชื่อบนwindowวัตถุในโหมดมาตรฐานเช่นกัน ทำไมพวกเขาถึงเปลี่ยนแปลงสิ่งนี้ ปรากฎว่ายังมีไซต์จำนวนมากที่ใช้ฟังก์ชันนี้ในโหมดมาตรฐาน ไมโครซอฟท์ยังได้เปิดตัวตัวอย่างการตลาดที่ป้องกันไม่ให้ตัวอย่างจากการทำงานใน Firefox

Webkit ได้พิจารณาสิ่งที่ตรงกันข้ามเมื่อเร็ว ๆ นี้ซึ่งมีการตั้งชื่อการเข้าถึงบนwindowวัตถุให้เป็นโหมด quirks เท่านั้น พวกเขาตัดสินใจโดยใช้เหตุผลเดียวกับ Gecko

ดังนั้น ... บ้าอย่างที่ดูเหมือนว่าพฤติกรรมนี้คือตอนนี้ปลอดภัยทางเทคนิคที่จะใช้ในรุ่นล่าสุดของเบราว์เซอร์ที่สำคัญทั้งหมดในโหมดมาตรฐาน แต่ในขณะที่ชื่อเข้าถึงสามารถดูเหมือนสะดวกบ้างก็ไม่ควรนำมาใช้

ทำไม? จำนวนมากของเหตุผลสามารถสรุปได้ในบทความนี้เกี่ยวกับสาเหตุที่ตัวแปรทั่วโลกที่ไม่ดี พูดง่ายๆคือการมีตัวแปรระดับโลกจำนวนมากนำไปสู่ข้อผิดพลาดที่มากขึ้น สมมติว่าคุณพิมพ์ชื่อของ a varและเกิดขึ้นกับการพิมพ์idโหนด DOM โดยบังเอิญโดยไม่ตั้งใจ

นอกจากนี้แม้จะเป็นมาตรฐาน แต่ก็ยังมีข้อขัดแย้งเล็กน้อยในการนำเบราว์เซอร์ของการเข้าถึงที่มีชื่อมาใช้

  • IE ทำให้ค่าของnameแอตทริบิวต์ที่สามารถเข้าถึงได้อย่างไม่ถูกต้องสำหรับองค์ประกอบของฟอร์ม (อินพุตเลือก ฯลฯ )
  • Gecko และ Webkit อย่างไม่ถูกต้องไม่<a>สามารถเข้าถึงแท็กผ่านnameแอตทริบิวต์ของพวกเขา
  • Gecko จัดการองค์ประกอบที่มีชื่อหลายชื่อไม่ถูกต้องด้วยชื่อเดียวกัน (จะส่งคืนการอ้างอิงไปยังโหนดเดียวแทนที่จะเป็นอาร์เรย์ของการอ้างอิง)

และฉันแน่ใจว่ามีมากขึ้นถ้าคุณลองใช้การเข้าถึงแบบมีชื่อในกรณีขอบ

ตามที่ระบุไว้ในคำตอบอื่น ๆ ที่ใช้document.getElementByIdจะได้รับการอ้างอิงไปยังโหนด DOM idโดยตัวของมัน หากคุณต้องการที่จะได้รับการอ้างอิงไปยังโหนดโดยตัวของมันใช้แอตทริบิวต์namedocument.querySelectorAll

โปรดโปรดอย่าเผยแพร่ปัญหานี้โดยใช้การเข้าถึงแบบกำหนดชื่อในไซต์ของคุณ นักพัฒนาเว็บจำนวนมากเสียเวลาพยายามติดตามพฤติกรรมที่มหัศจรรย์นี้ เราจำเป็นต้องดำเนินการและรับเครื่องมือการแสดงผลเพื่อปิดการเข้าถึงชื่อในโหมดมาตรฐาน ในระยะสั้นมันจะทำลายบางเว็บไซต์ที่ทำสิ่งไม่ดี แต่ในระยะยาวมันจะช่วยย้ายเว็บไปข้างหน้า

หากคุณสนใจฉันพูดคุยเกี่ยวกับเรื่องนี้ในรายละเอียดเพิ่มเติมเกี่ยวกับบล็อกของฉัน - https://www.tjvantoll.com/2012/07/19/dom-element-references-as-global-variables/


3
เพียงแค่ทราบถึงข้อแม้ที่ชัดเจนเพื่อหลักฐานว่า "มันไม่ควรใช้" นั่นคือ "ไม่ควรใช้จนกว่าคุณจะเป็นรหัสโคบาล" รหัสคาวบอยเพิ่งไปได้
Jeremy Foster

5
@ jeremyfoster เว้นแต่ "รหัสคาวบอย" หมายถึงคนที่ใช้และเผยแพร่การใช้งานที่ไม่เป็นมิตรกับนักพัฒนาฉันไม่เห็นด้วยอย่างยิ่ง
Patrick Roberts

2
เครื่องหมายหนึ่งของคาวบอยที่ดีคือหลายคนไม่เห็นด้วย แต่ตอนนี้ฉันชอบคาวบอยปรัชญาหรืออะไรทำนองนั้น
Jeremy Foster

ผู้คนจำนวนมากขึ้นควรใช้งานdocument.querySelectorAllและdocument.querySelectorเมื่อเข้าถึง DOM +1 สำหรับคำแนะนำที่ดีในการใช้สิ่งนั้น การเข้าถึงองค์ประกอบโดยตัวเลือกเป็นกระบวนการที่มีประสิทธิภาพมากขึ้นอย่างแน่นอน
เทรวิส J

20

คุณควรติดgetElementById()ในกรณีเหล่านี้ตัวอย่างเช่น:

document.getElementById('example').innerHTML

IE ชอบที่จะผสมผสานองค์ประกอบกับname และ IDคุณลักษณะในเนมสเปซส่วนกลางดังนั้นควรให้ชัดเจนเกี่ยวกับสิ่งที่คุณกำลังจะได้รับ


3

ใช่.

ทดสอบใน Chrome 55, Firefox 50, IE 11, IE Edge 14 และ Safari 10
ด้วยตัวอย่างต่อไปนี้:

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


1
นอกจากนี้ใน Opera อย่างไรก็ตามฉันคิดว่าการคัดค้านกลไกนี้ที่แสดงในหน้านี้เป็นสิ่งที่ดีมาก
ncmathsadist

1

คำถามควรฟัง :: "แท็ก HTML ที่มี ID ที่ให้กลายเป็นองค์ประกอบ DOM ที่เข้าถึงได้ทั่วโลกหรือไม่"

คำตอบคือใช่!

นั่นเป็นวิธีที่ใช้งานได้และนั่นเป็นสาเหตุที่รหัส W3C เริ่มขึ้นด้วย: รหัสของแท็ก HTML ในสภาพแวดล้อมการสคริปต์ที่แยกวิเคราะห์กลายเป็นตัวจัดการองค์ประกอบ DOM ที่สอดคล้องกัน

อย่างไรก็ตาม Netscape Mozilla ปฏิเสธที่จะปฏิบัติตาม (พวกเขาบุกรุก) W3C และเก็บไว้อย่างดื้อรั้นโดยใช้แอตทริบิวต์ชื่อที่เลิกใช้เพื่อสร้างความเสียหายและดังนั้นจึงทำลายฟังก์ชันการเขียนสคริปต์และความสะดวกในการเขียนโค้ด

หลังจากความล้มเหลวของ Netscape Navigator 4.7 นักพัฒนาของพวกเขาทุกคนไปและแทรกซึมเข้าไปใน W3C ในขณะที่ผู้ร่วมงานของพวกเขาถูกแทนที่เว็บด้วยการปฏิบัติที่ผิดและตัวอย่างที่ผิด การบังคับใช้และการใช้ซ้ำของแอตทริบิวต์ชื่อที่เลิกใช้แล้ว [! ซึ่งไม่ได้หมายความว่าจะไม่ซ้ำกัน] เมื่อเทียบกับคุณลักษณะ ID เพื่อให้สคริปต์ที่ใช้หมายเลขอ้างอิงสำหรับการเข้าถึงองค์ประกอบ DOM เฉพาะจะทำลาย!

และทำลายพวกเขาตามที่พวกเขาจะเขียนและเผยแพร่บทเรียนการเขียนโค้ดและตัวอย่างที่กว้างขวาง [เบราว์เซอร์ของพวกเขาจะไม่จดจำต่อไป] เช่น document.all.ElementID.propertyแทนที่จะElementID.propertyทำให้อย่างน้อยก็ไม่มีประสิทธิภาพและทำให้เบราว์เซอร์มีค่าใช้จ่ายมากขึ้น โดเมน HTML โดยใช้โทเค็นเดียวกันสำหรับชื่อ (ตอนนี้ [1996-97], เลิกใช้แล้ว) และแอตทริบิวต์ ID มาตรฐานที่ส่งด้วยค่าโทเค็นเดียวกัน

พวกเขาสามารถโน้มน้าวใจผู้สมัครงานเขียนโค้ดที่ไม่รู้ตัวได้อย่างง่ายดายว่าชื่อและรหัสนั้นเหมือนกันยกเว้นแอตทริบิวต์ ID นั้นสั้นกว่าและช่วยประหยัดไบต์และสะดวกกว่า coder มากกว่าคุณสมบัติชื่อโบราณ ซึ่งแน่นอนว่าเป็นเรื่องโกหก หรือ - ในบทความที่ตีพิมพ์เป็น HTML แทนที่บทความที่น่าเชื่อถือที่คุณจะต้องระบุทั้งชื่อและ ID ให้กับแท็กของคุณเพื่อให้สามารถเข้าถึงได้โดยเครื่องมือการเขียนสคริปต์

Mosaic Killers [ชื่อรหัสว่า "Mozilla"] โกรธมากพวกเขาคิดว่า "ถ้าเราลงไปอินเทอร์เน็ตก็ควรจะ"

Microsoft ที่เพิ่มขึ้น - ในทางกลับกันพวกเขาคิดว่าพวกเขาควรเลิกใช้งานและทำเครื่องหมายเพื่อลบชื่อคุณสมบัติและถือเสมือนว่าเป็น ID ที่เป็นตัวระบุที่ไม่ซ้ำกัน หน้าเก่าเขียนโดยผู้ฝึกอบรมของ Netscape พวกเขาผิดอย่างมหันต์ ...

และการกลับมาของคอลเลคชั่นอาร์เรย์ขององค์ประกอบที่ขัดแย้งกันของ ID ไม่ใช่วิธีแก้ไขปัญหาที่มนุษย์สร้างขึ้นโดยเจตนาเช่นกัน จริงๆแล้วมันเสียจุดประสงค์ทั้งหมด

และนี่คือเหตุผลเดียวที่ W3C หันกลับมาน่าเกลียดและทำให้เรางี่เง่าเช่นdocument.getElementByIdและที่มาพร้อมกับโรโคโค goddamn ไวยากรณ์ที่น่ารำคาญของการเรียงลำดับ ... (... )

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.