Benoemde element-ID's kunnen worden aangeduid als JavaScript Globals PlatoBlockchain Data Intelligence. Verticaal zoeken. Ai.

Benoemde element-ID's kunnen worden aangeduid als JavaScript-globalen

Wist u dat DOM-elementen met ID's in JavaScript toegankelijk zijn als globale variabelen? Het is een van die dingen die er altijd al zijn geweest, maar ik ben er echt voor het eerst in aan het graven.

Als dit de eerste keer is dat je erover hoort, zet je dan schrap! We kunnen het in actie zien door simpelweg een ID toe te voegen aan een element in HTML:

Normaal gesproken definiรซren we een nieuwe variabele met querySelector("#cool") or getElementById("cool") om dat element te selecteren:

var el = querySelector("#cool");

Maar we hebben eigenlijk al toegang tot #cool zonder die rigamorale:

Dus, elke id - of name attribuut, wat dat betreft โ€” in de HTML is toegankelijk in JavaScript met behulp van window[ELEMENT_ID]. Nogmaals, dit is niet echt "nieuw", maar het is echt ongewoon om te zien.

Zoals je misschien wel vermoedt, is toegang tot het globale bereik met benoemde verwijzingen niet het beste idee. Sommige mensen zijn dit de 'global scope-vervuiler' gaan noemen. We zullen ingaan op waarom dat zo is, maar eerst...

Enige context

Deze aanpak is beschreven in de HTML-specificatie, waar het wordt beschreven als "named toegang op de" Window object."

Internet Explorer was de eerste die de functie implementeerde. Alle andere browsers hebben het ook toegevoegd. Gecko was destijds de enige browser die het niet rechtstreeks in de standaardmodus ondersteunde, maar er in plaats daarvan voor koos om er een experimentele functie van te maken. Er was enige aarzeling om het uit te voeren, maar het is ging vooruit in naam van browsercompatibiliteit (Gecko probeerde zelfs om overtuig WebKit om het uit de standaardmodus te halen) en bereikte uiteindelijk de standaardmodus in Firefox 14.

Een ding dat misschien niet goed bekend is, is dat browsers een paar voorzorgsmaatregelen moesten nemen - met wisselend succes - om ervoor te zorgen dat gegenereerde globals de webpagina niet breken. Een van die maatregelen isโ€ฆ

Variabele schaduwwerking

Waarschijnlijk het meest interessante aan deze functie is dat verwijzingen naar benoemde elementen dat niet doen schaduw bestaande globale variabelen. Dus, als een DOM-element een . heeft id die al is gedefinieerd als een globaal, zal de bestaande niet overschrijven. Bijvoorbeeld:


  
    window.foo = "bar";
  


  
I won't override window.foo
console.log(window.foo); // Prints "bar"

En het tegenovergestelde is ook waar:

I will be overridden :(
window.foo = "bar"; console.log(window.foo); // Prints "bar"

Dit gedrag is essentieel omdat het gevaarlijke overrides teniet doet, zoals:

, die anders een conflict zou veroorzaken door het ongeldig maken van de alert API. Deze beveiligingstechniek is misschien wel de reden waarom je - als je op mij lijkt - hier voor het eerst over leert.

De zaak tegen genoemde globals

Eerder zei ik dat het misschien niet het beste idee is om globale benoemde elementen als referenties te gebruiken. Daar zijn veel redenen voor, die TJ VanToll heeft mooi verslag gedaan op zijn blog en ik zal het hier samenvatten:

  • Als de DOM verandert, verandert ook de referentie. Dat maakt sommige echt "bros" (de spec's term for it) code waar de scheiding van zorgen tussen HTML en JavaScript te veel zou kunnen zijn.
  • Toevallige verwijzingen zijn veel te gemakkelijk. Een simpele typefout kan heel goed eindigen met het verwijzen naar een genoemde globale en onverwachte resultaten opleveren.
  • Het wordt anders geรฏmplementeerd in browsers. We zouden bijvoorbeeld toegang moeten hebben tot een anker met een id - bijv โ€” maar sommige browsers (namelijk Safari en Firefox) retourneren a ReferenceError in de console.
  • Het geeft misschien niet terug wat je denkt. Volgens de specificatie, wanneer er meerdere exemplaren van hetzelfde benoemde element in de DOM zijn, bijvoorbeeld twee exemplaren van

    โ€” de browser zou een . moeten teruggeven HTMLCollection met een array van de instanties. Firefox retourneert echter alleen de eerste instantie. Nogmaals, de specificatie zegt: we zouden รฉรฉn instantie van an . moeten gebruiken id in ieder geval in de boom van een element. Maar dit zal niet voorkomen dat een pagina werkt of iets dergelijks.

  • Misschien zijn er prestatiekosten? Ik bedoel, de browser moet die lijst met referenties maken en onderhouden. Een paar mensen hebben tests uitgevoerd in deze StackOverflow-thread, waar benoemde globals eigenlijk waren beter presteren in รฉรฉn test en minder presterend in een recentere test.

Aanvullende overwegingen

Laten we zeggen dat we de kritiek op het gebruik van benoemde globals weggooien en ze toch gebruiken. Het is al goed. Maar er zijn een aantal dingen die u misschien wilt overwegen als u dat doet.

Polyvullingen

Hoe scherp het ook klinkt, dit soort globale controles zijn een typische instellingsvereiste voor polyfills. Bekijk het volgende voorbeeld waarin we een cookie plaatsen met behulp van de nieuwe CookieStore API, polyfilling in browsers die het nog niet ondersteunen:


  
  
    // Polyfill the CookieStore API if not yet implemented.
    // https://developer.mozilla.org/en-US/docs/Web/API/CookieStore
    if (!window.cookieStore) {
      window.cookieStore = myCookieStorePolyfill;
    }
    cookieStore.set("foo", "bar");
  

Deze code werkt prima in Chrome, maar geeft de volgende foutmelding in Safari.:

TypeError: cookieStore.set is not a function

Safari heeft geen ondersteuning voor de CookieStore API op het moment van schrijven. Als gevolg hiervan wordt de polyfill niet toegepast omdat de img element ID creรซert een globale variabele die botst met de cookieStore global.

JavaScript API-updates

We kunnen de situatie omdraaien en nog een ander probleem vinden waarbij updates van de JavaScript-engine van de browser de globale verwijzingen van een benoemd element kunnen verbreken.

Bijvoorbeeld:


  
  
    window.BarcodeDetector.focus();
  

Dat script grijpt een verwijzing naar het invoerelement en roept focus() ben ermee bezig. Het werkt correct. Toch weten we niet hoe lang het zal blijven werken.

Zie je, de globale variabele die we gebruiken om naar het invoerelement te verwijzen, zal stoppen met werken zodra browsers de . gaan ondersteunen BarcodeDetector API. Op dat moment is de window.BarcodeDetector global zal niet langer een verwijzing zijn naar het invoerelement en .focus() zal een "window.BarcodeDetector.focus is geen functieโ€ fout.

Bonus: niet alle benoemde elementen genereren globale referenties

Wil je iets grappigs horen? Om het nog erger te maken, zijn benoemde elementen alleen toegankelijk als globale variabelen als de namen niets anders dan letters bevatten. Browsers maken geen globale referentie voor een element met een ID die speciale tekens en cijfers bevat, zoals hello-world en item1.

Conclusie

Laten we samenvatten hoe we hier zijn gekomen:

  • Alle belangrijke browsers creรซren automatisch globale verwijzingen naar elk DOM-element met een id (of, in sommige gevallen, een name attribuut).
  • Toegang tot deze elementen via hun wereldwijde referenties is onbetrouwbaar en potentieel gevaarlijk. Gebruiken querySelector or getElementById gebruiken.
  • Aangezien globale verwijzingen automatisch worden gegenereerd, kunnen ze enkele bijwerkingen hebben op uw code. Dat is een goede reden om het gebruik van de id attribuut tenzij je het echt nodig hebt.

Uiteindelijk is het waarschijnlijk een goed idee om het gebruik van benoemde globals in JavaScript te vermijden. Ik citeerde eerder de specificatie over hoe het leidt tot "brosse" code, maar hier is de volledige tekst om het punt naar huis te brengen:

Als algemene regel geldt dat het vertrouwen hierop zal leiden tot broze code. Welke ID's uiteindelijk aan deze API worden toegewezen, kan in de loop van de tijd variรซren, bijvoorbeeld omdat er nieuwe functies aan het webplatform worden toegevoegd. Gebruik in plaats hiervan document.getElementById() or document.querySelector().

Ik denk dat het feit dat de HTML-specificatie zelf aanbeveelt om weg te blijven van deze functie voor zich spreekt.

Tijdstempel:

Meer van CSS-trucs