Skip to content
This page has been auto-translated and may contain errors.View in English

DOM

docs.scrimba.com

आपकी HTML फाइल एक बार लोड होती है, और फिर पेज वहीं बैठ जाता है। लेकिन एक सर्च बॉक्स जो आप टाइप करते हुए परिणामों का सुझाव देता है, एक मेनू जो क्लिक पर खुलता है, एक काउंटर जो बढ़ता है, इनमें से कोई भी HTML फाइल में नहीं है। कुछ लोड होने के बाद पेज पर जो कुछ दिखता है उसे बदलता है, और वह कुछ JavaScript है जो DOM के माध्यम से पेज में पहुंचता है। यह अध्याय उस पहुंच के बारे में है: JavaScript कैसे पेज के हिस्सों को ढूंढता है और उन्हें बदलता है ताकि पेज पाठक के सामने अपडेट हो।

DOM क्या है

जब ब्राउज़र आपके पेज को लोड करता है, तो यह आपके HTML को पढ़ता है और इसमें से एक ऑब्जेक्ट्स का ट्री बनाता है: पेज के लिए एक ऑब्जेक्ट, <body> के लिए एक, और अंदर के हर हेडिंग, पैराग्राफ और बटन के लिए एक। यह ट्री DOM है, Document Object Model का संक्षिप्त रूप। आपका JavaScript इस ट्री को पढ़ सकता है और इसे बदल सकता है, और जब यह करता है, तो आप जो पेज देखते हैं वह तुरंत अपडेट हो जाता है।

जो बात याद रखने लायक है: DOM आपकी HTML फाइल नहीं है। यह पेज का लाइव संस्करण है, ब्राउज़र की मेमोरी में बैठा हुआ है। आपकी .html फाइल शुरुआती रेसिपी है; DOM वह तैयार डिश है जो ब्राउज़र परोस रहा है, और JavaScript सभी के खाने के दौरान प्लेट को फिर से व्यवस्थित कर सकता है।

DOM (Document Object Model) वह मेमोरी में ट्री है जो ब्राउज़र आपके HTML से बनाता है। हर एलिमेंट एक ऑब्जेक्ट बन जाता है, उसी तरह नेस्ट किया गया जैसे आपके टैग नेस्ट किए गए हैं: <body> एक <main> रखता है, जो एक <section> रखता है, जो एक पैराग्राफ रखता है। JavaScript को ग्लोबल document के माध्यम से इस ट्री तक पहुंच मिलता है, और वहां से यह ट्री में चल सकता है, किसी भी एलिमेंट को पढ़ सकता है, और इसे बदल सकता है।

वह अंतर जो बाद में आपको भ्रम से बचाता है: DOM आपके सोर्स HTML से अलग है। HTML एक बार पार्स किया जाता है ट्री बनाने के लिए; उसके बाद, ट्री ही लाइव है। DOM को बदलें और पेज अपडेट हो जाता है; आपकी डिस्क पर मूल HTML फाइल कभी नहीं बदलती। यही कारण है कि "view source" एक बार JavaScript चलने के बाद आप जो स्क्रीन पर देखते हैं उससे कुछ नहीं हो सकता है।

DOM दस्तावेज़ का ब्राउज़र का लाइव ऑब्जेक्ट मॉडल है: एक ट्री of नोड्स (एलिमेंट्स, टेक्स्ट, कमेंट्स, और दस्तावेज़ स्वयं) जो ब्राउज़र आपके HTML को पार्स करके बनाता है, और जिसे यह रेंडर करता है। यह एक भाषा-तटस्थ API है, document और इससे संबंधित ऑब्जेक्ट्स के माध्यम से JavaScript को उजागर किया गया है, लेकिन JavaScript भाषा का हिस्सा नहीं है; यह एक ब्राउज़र फीचर है जो रनटाइम प्रदान करता है।

जो फ्रेमिंग व्यावहारिक रूप से मायने रखती है: HTML सोर्स एक इनपुट है, एक बार ट्री में पार्स किया गया है, और DOM उसके बाद सच्चाई का स्रोत है। आपकी स्क्रिप्ट्स चलने के बाद document.body.innerHTML को पढ़ें और आपको वर्तमान सीरीएलाइज़्ड ट्री मिलता है, वह बाइट्स नहीं जो आपने भेजे थे। यह भी इसलिए है कि DOM सीधे HTML से आता है: जो टैग आप लिखते हैं वह प्रारंभिक ट्री को परिभाषित करते हैं, और जो कुछ भी JavaScript करता है वह उस ट्री को संपादित करना है। DOM में हेरफेर करने की कीमत होती है जो सोर्स में नहीं होती है, क्योंकि बदलाव ब्राउज़र को लेआउट फिर से कंप्यूट करने और फिर से पेंट करने के लिए ट्रिगर कर सकते हैं, जो वह थ्रेड है जिसे आप नीचे उन्नत अनुभागों में अनुसरण करते हैं।

DOM में हर एलिमेंट एक ऑब्जेक्ट है, उसी तरह का जो आपने objects में देखा था, उन प्रॉपर्टीज़ के साथ जिन्हें आप पढ़ सकते हैं और बदल सकते हैं। यह पूरा ट्रिक है: क्योंकि पेज ऑब्जेक्ट्स हैं, और आप पहले से ही जानते हैं कि ऑब्जेक्ट्स के साथ कैसे काम करना है, पेज को बदलना ऑब्जेक्ट प्रॉपर्टीज़ को बदलना है।

JunoDOM क्या है ब्राउज़र आपके HTML को ऑब्जेक्ट्स के एक ट्री में बदलता है जिसे DOM कहते हैं, और यह ट्री लाइव पेज है। आपकी HTML फाइल रेसिपी है; DOM परोसा जा रहा भोजन है, और JavaScript इसे मेज पर बदल सकता है। हर एलिमेंट एक ऑब्जेक्ट है, इसलिए पेज को बदलना ऑब्जेक्ट प्रॉपर्टीज़ को बदलना है।
JunoDOM क्या है DOM मेमोरी में ट्री है जो ब्राउज़र आपके HTML से बनाता है, document के माध्यम से पहुंचा जाता है। यह आपकी सोर्स फाइल से अलग है: एक बार पार्स करें, फिर ट्री ही लाइव है, यही कारण है कि "view source" आप जो देखते हैं उससे अलग हो सकता है। ट्री को बदलें और पेज अपडेट हो जाता है।
JunoDOM क्या है DOM नोड्स का एक ट्री है जो ब्राउज़र HTML से पार्स करता है और जिससे रेंडर करता है; यह एक ब्राउज़र API है, भाषा का हिस्सा नहीं है। सोर्स एक इनपुट है एक बार पार्स किया गया है, ट्री उसके बाद सच्चाई है, इसलिए innerHTML वर्तमान ट्री को दर्शाता है, आपके भेजे गए बाइट्स को नहीं। संपादन लेआउट और फिर से पेंट की कीमत कर सकते हैं, यही कारण है कि लिखने के पैटर्न बाद में मायने रखते हैं।

एलिमेंट्स को चुनना

इससे पहले कि आप किसी एलिमेंट को बदल सकें, आपको इसे ट्री में खोजना होगा। आप इसे उसी तरह इंगित करते हैं जैसे CSS करता है, एक सिलेक्टर के साथ, और ब्राउज़र आपको मिलान करने वाली ऑब्जेक्ट वापस देता है।

कर्मठ है document.querySelector। आप इसे एक CSS सिलेक्टर देते हैं, उसी तरह का पैटर्न जिसका उपयोग आप CSS में करते हैं, और यह पहला एलिमेंट जो मेल खाता है:

js
const card = document.querySelector(".card"); // class="card" वाला पहला एलिमेंट
const total = document.querySelector("#total"); // id="total" वाला एलिमेंट

.card क्लास द्वारा मेल खाता है, #total आईडी द्वारा मेल खाता है, और एक सादा शब्द जैसे "button" टैग नाम द्वारा मेल खाता है। querySelector आपको पहला मेल देता है और वहीं रुक जाता है। जब आप हर मेल चाहते हैं, तो querySelectorAll का उपयोग करें, जो एक सूची लूप करने के लिए लौटाता है:

js
const cards = document.querySelectorAll(".card"); // class="card" वाले सभी एलिमेंट्स
console.log(cards.length); // इसे कितने मिले

अगर कुछ भी मेल नहीं खाता, querySelector null लौटाता है, जो JavaScript का तरीका है कहने का "यहां कुछ नहीं है"।

document.querySelector किसी भी CSS सिलेक्टर को लेता है और पहले मिलान एलिमेंट को लौटाता है, या यदि कोई मेल नहीं है तो nulldocument.querySelectorAll सभी मेलों को एक सूची के रूप में लौटाता है:

js
const toggle = document.querySelector(".menu-toggle"); // पहला मेल, या null
const items = document.querySelectorAll(".card"); // हर मेल, एक सूची के रूप में

सिलेक्टर पूर्ण CSS हैं, केवल क्लास और आईडी नहीं: querySelector("nav a") नेव के अंदर पहली लिंक खोजता है, querySelector("input[type='email']") एट्रिब्यूट द्वारा मेल खाता है। जो कुछ भी इसे स्टाइलशीट में चुनता है वह इसे यहां चुनता है।

null रिटर्न वह है जिसके लिए आपको योजना बनानी चाहिए। क्योंकि एक मिस null है, document.querySelector(".missing").textContent जैसा कोड थ्रो करता है, क्योंकि आप null की प्रॉपर्टी नहीं पढ़ सकते। जब एक एलिमेंट मौजूद नहीं हो सकता, पहले जांचें: if (toggle) { ... }

document.querySelector(selector) दस्तावेज़ क्रम में CSS सिलेक्टर से मिलान करने वाला पहला एलिमेंट लौटाता है, या null; document.querySelectorAll(selector) सभी मेलों की एक NodeList लौटाता है। दोनों पूर्ण CSS सिलेक्टर व्याकरण स्वीकार करते हैं, इसलिए कम्बिनेटर, एट्रिब्यूट सिलेक्टर, और छद्म-क्लासेस सभी काम करते हैं:

js
const firstError = document.querySelector(".form .field.is-invalid input");
const externalLinks = document.querySelectorAll("a[href^='http']");

परिणाम की दो प्रॉपर्टीज़ जानने के लिए लायक हैं। पहला, querySelectorAll से NodeList स्थिर है: यह कॉल टाइम पर लिया गया एक स्नैपशॉट है, इसलिए पेज में जोड़े गए एलिमेंट्स इसमें दिखाई नहीं देते। यह पुराने API के विपरीत है (getElementsByClassName, getElementsByTagName), जो एक लाइव HTMLCollection लौटाते हैं जो स्वयं को अपडेट करता है क्योंकि DOM बदलता है; आखिरी अनुभाग में उस अंतर के बारे में अधिक जानकारी। दूसरा, स्कोपिंग प्रदर्शन और सटीकता के लिए मायने रखता है: document के बजाय एक एलिमेंट पर querySelector को कॉल करने से केवल उस एलिमेंट के सबट्री को खोजा जाता है (card.querySelector(".title")), जो बड़े पेजों पर तेज़ और गलत जगह से कुछ मेल खाने से सुरक्षित दोनों है। जब भी आप पहले से कंटेनर रखते हैं तो स्कोप्ड फॉर्म तक पहुंचें।

Junoएलिमेंट्स को चुनना एक एलिमेंट खोजने के लिए, document.querySelector को .card या #total जैसे CSS सिलेक्टर दें, और यह आपको पहला मेल देता है। querySelectorAll का उपयोग करें जब आप सभी को एक सूची के रूप में चाहते हैं। अगर कुछ भी मेल नहीं खाता तो आपको null मिलता है, जिसका अर्थ है "यहां कुछ नहीं है"।
Junoएलिमेंट्स को चुननाquerySelector पहला मेल लौटाता है, querySelectorAll हर मेल को एक सूची के रूप में लौटाता है, और दोनों कोई भी CSS सिलेक्टर लेते हैं जिसका उपयोग आप स्टाइलशीट में करेंगे। एक मिस null लौटाता है, इसलिए इसे एक प्रॉपर्टी पढ़ना थ्रो करता है; जब एलिमेंट वहां नहीं हो सकता तो if (element) से गार्ड करें।
Junoएलिमेंट्स को चुनना दोनों तरीके पूर्ण CSS सिलेक्टर लेते हैं; querySelectorAll एक स्थिर NodeList हाथ में देता है, एक स्नैपशॉट जो बाद में जोड़े गए लोगों को नहीं देखेगा। document नहीं बल्कि एक एलिमेंट पर querySelector को कॉल करें केवल इसके सबट्री को खोजने के लिए, जो तेज़ है और पेज भर में कुछ मेल खाने से बचता है। और याद रखें एक मिस null है।

एलिमेंट्स को पढ़ना और बदलना

एक बार जब आप एक एलिमेंट रखते हैं, तो आप इसे इसकी प्रॉपर्टीज़ के माध्यम से पढ़ते और बदलते हैं, उसी तरह जैसे आप किसी भी ऑब्जेक्ट को पढ़ते और बदलते हैं। यह वह जगह है जहां पेज वास्तव में चलने लगता है।

प्रॉपर्टी जिसका आप सबसे अधिक उपयोग करेंगे वह textContent है, एक एलिमेंट के अंदर का टेक्स्ट। आप इसे पढ़ सकते हैं या सेट कर सकते हैं:

js
const total = document.querySelector("#total");
total.textContent = "42 items"; // पेज अब "42 items" दिखाता है

कुछ कैसे दिखता है यह बदलने के लिए, आप आमतौर पर एक क्लास जोड़ते हैं या हटाते हैं और CSS को स्टाइलिंग करने देते हैं। classList के पास इसके लिए तीन तरीके हैं:

js
const card = document.querySelector(".card");
card.classList.add("selected"); // एक क्लास जोड़ें
card.classList.remove("selected"); // इसे दूर ले जाएं
card.classList.toggle("selected"); // जोड़ें अगर गायब है, हटाएं अगर है

आप .style के माध्यम से एक एकल स्टाइल को सीधे सेट कर सकते हैं, और setAttribute के साथ src या href जैसे एट्रिब्यूट सेट कर सकते हैं:

js
card.style.color = "crimson"; // एक इनलाइन स्टाइल
const avatar = document.querySelector(".avatar");
avatar.setAttribute("src", "delhi.jpg"); // इमेज सोर्स सेट करें

पहले classList तक पहुंचें और .style केवल एकबारगी ट्वीक्स के लिए, क्योंकि आपकी स्टाइलिंग को CSS में रखना इसे एक जगह पर रखता है।

textContent एक एलिमेंट के अंदर का टेक्स्ट पढ़ता और लिखता है। classList क्लासेस को टॉगल करता है इसलिए स्टाइलिंग आपके CSS में रहता है। .style व्यक्तिगत इनलाइन स्टाइल्स सेट करता है, और setAttribute किसी भी एट्रिब्यूट को सेट करता है:

js
const badge = document.querySelector(".badge");
badge.textContent = `${count} new`; // टेक्स्ट सेट करें
badge.classList.toggle("is-hidden", count === 0); // एक शर्त के साथ टॉगल करें
badge.setAttribute("aria-label", `${count} new messages`); // एट्रिब्यूट सेट करें

classList.toggle एक वैकल्पिक दूसरा आर्गुमेंट लेता है: एक बूलियन जो क्लास को true होने पर चालू करता है और false होने पर बंद करता है, जो add और remove के चारों ओर if/else की तुलना में साफ़ है।

चेतावनी जो जल्दी दी जानी चाहिए: innerHTML भी है, जो एक एलिमेंट की सामग्री को कच्चे HTML के रूप में सेट करता है, टैग और सभी। यह लुभावना है क्योंकि यह लचीला दिखता है, लेकिन किसी भी टेक्स्ट के लिए innerHTML नहीं बल्कि textContent का उपयोग करें जो किसी यूजर से आया है। यूजर इनपुट से innerHTML सेट करना उस इनपुट को वास्तविक HTML को आपके पेज में इंजेक्ट करने देता है, जो एक सुरक्षा खतरा है। जब आप सादा टेक्स्ट सेट कर रहे हैं, textContent वैसे भी सही टूल है।

पढ़ने-और-लिखने की सतह व्यापक है, लेकिन चार प्रॉपर्टीज़ अधिकांश काम करती हैं: टेक्स्ट के लिए textContent, स्थिति क्लासेस के लिए classList, कंप्यूटेड एकबारगी स्टाइल्स के लिए .style, और एट्रिब्यूट्स के लिए setAttribute.style की जगह classList को प्राथमिकता दें इसलिए प्रस्तुति CSS में रहता है और JavaScript केवल स्थिति क्लासेस को फ्लिप करता है (जैसे is-open या is-loading क्लासेस जिन्हें आपकी स्टाइलशीट फिर स्टाइल करती है):

js
const panel = document.querySelector(".panel");
panel.classList.toggle("is-open", shouldOpen);
panel.setAttribute("aria-expanded", String(shouldOpen)); // एट्रिब्यूट्स स्ट्रिंग हैं

तीव्र किनारा innerHTML है। इसे सेट करना स्ट्रिंग को HTML के रूप में पार्स करता है और इससे वास्तविक नोड्स बनाता है, इसलिए उस स्ट्रिंग में कोई भी मार्कअप लाइव हो जाता है: एक <script> या एक onerror हैंडलर यूजर-आपूर्ति किए गए टेक्स्ट में आपके पेज में चलता है। यह क्रॉस-साइट स्क्रिप्टिंग (XSS) है: डेटा के माध्यम से कार्यकारी सामग्री को इंजेक्ट करना जिसे आपने टेक्स्ट के रूप में माना। textContent कभी HTML को पार्स नहीं करता; यह टेक्स्ट सेट करता है और केवल टेक्स्ट, इसलिए यह सुरक्षित डिफ़ॉल्ट है और तेज़ एक है, क्योंकि ब्राउज़र HTML पार्स को छोड़ देता है। innerHTML को मार्कअप तक सीमित रखें जिसे आप पूरी तरह से नियंत्रित करते हैं, और कभी यूजर इनपुट को जोड़कर यह न बनाएं। जब आपको यूजर डेटा को संरचित मार्कअप में डालने की आवश्यकता हो, संरचना को सुरक्षित तरीकों से सेट करें और अविश्वसनीय मूल्य को textContent के माध्यम से छोड़ें, जो पैटर्न है जो अगला अनुभाग की ओर बढ़ता है।

एट्रिब्यूट्स पर एक और नोट: setAttribute HTML एट्रिब्यूट (एक स्ट्रिंग) लिखता है, जबकि कई एलिमेंट्स एक लाइव प्रॉपर्टी को भी उजागर करते हैं जो भिन्न हो सकती है। input.value दर्शाता है कि यूजर ने अभी क्या टाइप किया है; input.getAttribute("value") मार्कअप से मूल डिफ़ॉल्ट लौटाता है। फॉर्म फील्ड्स के लिए, एट्रिब्यूट नहीं प्रॉपर्टी पढ़ें।

Junoएलिमेंट्स को पढ़ना और बदलना एक एलिमेंट के अंदर टेक्स्ट textContent के साथ सेट करें, और classList.add, remove, और toggle के साथ एक क्लास जोड़कर या हटाकर इसका लुक बदलें। एक एकबारगी ट्वीक के लिए .style का उपयोग करें और इमेज सोर्स जैसी चीज़ों के लिए setAttribute करें। क्लासेस पर झुकें ताकि आपकी स्टाइलिंग आपके CSS में रहे।
Junoएलिमेंट्स को पढ़ना और बदलना टेक्स्ट के लिए textContent, स्थिति क्लासेस के लिए classList, एकबारगी के लिए .style, एट्रिब्यूट्स के लिए setAttribute; classList.toggle कोई बूलियन भी लेता है इसे चालू या बंद करने के लिए। किसी भी चीज़ के लिए innerHTML से दूर रहें जो एक यूजर ने टाइप की है, क्योंकि यह वास्तविक HTML को आपके पेज में इंजेक्ट करता है। सादा टेक्स्ट के लिए, textContent बिना पर सही टूल है।
Junoएलिमेंट्स को पढ़ना और बदलनाclassList के साथ स्थिति क्लासेस को फ्लिप करें और स्टाइलिंग को CSS में रखें; एट्रिब्यूट्स के लिए setAttribute का उपयोग करें, याद रखें कि वह स्ट्रिंग हैं। innerHTML इसकी स्ट्रिंग को लाइव HTML के रूप में पार्स करता है, इसलिए यूजर डेटा इसमें एक XSS होल है; textContent कभी पार्स नहीं करता और दोनों सुरक्षित और तेज़ है। और फॉर्म फील्ड्स के लिए लाइव value प्रॉपर्टी पढ़ें, एट्रिब्यूट नहीं।

एलिमेंट्स बनाना और हटाना

जो एलिमेंट्स पहले से मौजूद हैं उन्हें बदलना आपको बहुत दूर ले जाता है, लेकिन कभी-कभी वहां कुछ नहीं होता: एक to-do जिसे आप जोड़ रहे हैं, एक सर्च परिणाम आ रहा है। इसके लिए आप नए एलिमेंट्स बनाते हैं और उन्हें ट्री में डालते हैं, और पुराने को निकालते हैं।

आप document.createElement के साथ एक नया एलिमेंट बनाते हैं, इसे कुछ सामग्री देते हैं, फिर append के साथ इसे पेज पर जोड़ते हैं:

js
const list = document.querySelector(".todo-list");
const item = document.createElement("li"); // एक नया <li>, पेज पर अभी नहीं
item.textContent = "दूध खरीदें"; // इसे कुछ टेक्स्ट दें
list.append(item); // अब यह सूची के अंत में दिखाई देता है

createElement से एक नया एलिमेंट केवल मेमोरी में मौजूद रहता है जब तक आप इसे कहीं append नहीं करते; वह कदम है जो इसे पेज पर डालता है। एक एलिमेंट को पेज से निकालने के लिए, इसे remove को कॉल करें:

js
item.remove(); // पेज से चला गया

document.createElement(tag) एक एलिमेंट बनाता है, append इसे माता-पिता के अंतिम बच्चे के रूप में जोड़ता है, और remove एक एलिमेंट को ट्री से निकालता है:

js
const list = document.querySelector(".todo-list");
const item = document.createElement("li");
item.textContent = "दूध खरीदें"; // सुरक्षित: टेक्स्ट, HTML के रूप में पार्स नहीं
item.classList.add("todo-item");
list.append(item); // पेज पर अटैच करें

Append करने से पहले textContent के साथ टेक्स्ट सेट करें, HTML स्ट्रिंग बनाकर नहीं, इसलिए यूजर-प्रविष्ट टेक्स्ट कभी मार्कअप को इंजेक्ट नहीं कर सकता। append सादा स्ट्रिंग्स और एक बार में कई नोड्स भी स्वीकार करता है (list.append(item, "or", another)), जो मिश्रित सामग्री के लिए सुविधाजनक है।

एक विवरण जो लोगों को पकड़ता है: एक एलिमेंट बनाना अपने आप में कुछ दृश्यमान नहीं करता। यह मेमोरी में तब तक बैठता है जब तक आप इसे कुछ ऐसा से अटैच नहीं करते जो पहले से ही ट्री में है। तब तक यह वास्तविक है लेकिन ऑफ़स्क्रीन है, जो बिल्कुल वह प्रॉपर्टी है जिसे उन्नत अनुभाग कुशलतापूर्वक बनाने के लिए उपयोग करता है।

createElement एक अलग नोड बनाता है, append नोड्स (या स्ट्रिंग्स) को माता-पिता के अंतिम बच्चों के रूप में डालता है, और remove ट्री से नोड को अलग करता है। दक्षता प्रश्न दिलचस्प है, क्योंकि लाइव ट्री में सम्मिलन की कीमत हो सकती है।

हर बार जब आप DOM को एक तरीके से बदलते हैं जो ज्यामिति को प्रभावित करता है, ब्राउज़र को पदों और आकारों को फिर से कंप्यूट करना पड़ सकता है (reflow, जिसे लेआउट भी कहा जाता है) और फिर फिर से पेंट करना पड़ सकता है। एक लूप के अंदर जो करें, लाइव पेज पर प्रति पुनरावृत्ति एक नोड जोड़ें, और आप उस काम को बार-बार ट्रिगर कर सकते हैं। फिक्स बंद-DOM बनाना और एक बार सम्मिलित करना है। DocumentFragment बिल्कुल इसके लिए एक हल्का, ऑफ़स्क्रीन कंटेनर है: आप नोड्स को फ्रैगमेंट में जोड़ते हैं (जो लाइव ट्री में नहीं है, इसलिए कोई reflow नहीं), फिर फ्रैगमेंट को एक बार जोड़ते हैं, जो अपने बच्चों को एक ऑपरेशन में डालता है:

js
const list = document.querySelector(".results");
const fragment = document.createDocumentFragment(); // ऑफ़स्क्रीन कंटेनर

for (const name of names) {
  const li = document.createElement("li");
  li.textContent = name; // यूजर डेटा का सुरक्षित सम्मिलन
  fragment.append(li); // कोई reflow नहीं: फ्रैगमेंट बंद-DOM है
}

list.append(fragment); // लाइव ट्री में एक सम्मिलन

फ्रैगमेंट को जोड़ना इसे माता-पिता में खाली कर देता है, इसलिए फ्रैगमेंट स्वयं DOM में नहीं दिखाई देता; केवल इसके बच्चे ही दिखाई देते हैं। एक ही सिद्धांत एक व्यापक आदत को चलाता है: DOM लिखों को बैच करें। एक लेआउट प्रॉपर्टी पढ़ना (जैसे offsetHeight) ब्राउज़र को लंबित लेआउट को फ्लश करने के लिए मजबूर करता है, इसलिए एक लूप में पढ़ों और लिखों को इंटरलीव करना लेआउट thrash का कारण बनता है, बार-बार मजबूर करता है reflows। पहले अपने पढ़ों को समूहबद्ध करें, फिर अपने लिखों को समूहबद्ध करें। कुछ नोड्स के लिए इनमें से कोई भी मायने नहीं रखता; सैकड़ों के लिए यह चिकना और खस्ता के बीच का अंतर है।

Junoएलिमेंट्स बनाना और हटानाdocument.createElement के साथ एक नया एलिमेंट बनाएं, textContent के साथ इसे टेक्स्ट दें, और append के साथ इसे पेज पर डालें। एक ताजा एलिमेंट केवल मेमोरी में रहता है जब तक आप इसे append नहीं करते, इसलिए वह कदम है जो इसे दिखाता है। इसे पेज से निकालने के लिए, इसे remove को कॉल करें।
Junoएलिमेंट्स बनाना और हटानाcreateElement इसे बनाता है, append इसे अंतिम बच्चे के रूप में अटैच करता है, remove इसे निकालता है। Append करने से पहले HTML स्ट्रिंग बनाने के बजाय textContent के साथ टेक्स्ट सेट करें, इसलिए कोई भी यूजर ने टाइप किया वह कभी मार्कअप को इंजेक्ट नहीं कर सकता। याद रखें एक बनाया गया एलिमेंट अदृश्य रहता है जब तक आप इसे कुछ ऐसा से अटैच नहीं करते जो पहले से पेज पर है।
Junoएलिमेंट्स बनाना और हटाना एक लूप में लाइव ट्री को append करना हर बार reflow को ट्रिगर कर सकता है; बंद-DOM में DocumentFragment में बनाएं और एक बार इसे append करें ताकि बच्चे एक साथ चले जाएं। एक लूप के बीच एक लेआउट प्रॉपर्टी पढ़ना लेआउट को मजबूर करता है और thrash का कारण बनता है, इसलिए अपने पढ़ों को बैच करें फिर अपने लिखों को बैच करें। कुछ नोड्स के लिए यह उपेक्षणीय है; सैकड़ों के लिए यह चिकना बनाम खस्ता है।

DOM आगे कहां जाता है

चुनना, पढ़ना, बदलना, बनाना, और हटाना अधिकांश कवर करता है कि JavaScript एक पेज के लिए क्या करता है, और यह सब अंदर एक ही कदम है: ट्री में एक ऑब्जेक्ट खोजें और इसकी प्रॉपर्टीज़ को बदलें। क्योंकि DOM ऑब्जेक्ट्स हैं, आप जो कुछ सीखते हैं objects में सीधे यहां लागू होता है, और इस अध्याय में तरीकों का छोटा सेट (querySelector, textContent, classList, createElement, append) अधिकांश टूलकिट है।

अब तक जो गायब है वह समय है। हर उदाहरण यहां एक बार चलता है, शीर्ष से नीचे तक, लेकिन एक वास्तविक पेज यूजर क्या करता है इसके जवाब में बदलता है: एक क्लिक, एक keystroke, एक सबमिट किया गया फॉर्म। आपके DOM बदलावों को उन पलों तक तार करना events है, अगला अध्याय, जहां addEventListener "यूजर ने यह किया" को "इसलिए पेज वह करता है" से जोड़ता है। एक बार चुनना और बदलना events के जवाब में बैठ जाता है, आप इंटरैक्टिव पेज बना सकते हैं जो इस हैंडबुक का लक्ष्य है।