Namngivna element-ID:n kan refereras till som JavaScript Globals PlatoBlockchain Data Intelligence. Vertikal sökning. Ai.

Namngivna element-ID kan hänvisas till som JavaScript-global

Visste du att DOM-element med ID är tillgängliga i JavaScript som globala variabler? Det är en av de saker som har funnits, typ för evigt, men jag gräver verkligen i det för första gången.

Om det här är första gången du hör talas om det, gör dig beredd! Vi kan se det i aktion helt enkelt genom att lägga till ett ID till ett element i HTML:

Normalt skulle vi definiera en ny variabel med hjälp av querySelector("#cool") or getElementById("cool") för att välja det elementet:

var el = querySelector("#cool");

Men vi har faktiskt redan tillgång till #cool utan det där rigorala:

Så, vilken som helst id - eller name attribut, för den delen — i HTML kan nås i JavaScript med hjälp av window[ELEMENT_ID]. Återigen, det här är inte precis "nytt" men det är verkligen ovanligt att se.

Som du kanske gissar är det inte den bästa idén att komma åt det globala omfånget med namngivna referenser. Vissa människor har kommit att kalla detta "den globala förorenaren". Vi kommer in på varför det är så, men först...

Vissa sammanhang

Denna metod är beskrivs i HTML-specifikationen, där det beskrivs som "namngiven åtkomst på Window objekt."

Internet Explorer var först med att implementera funktionen. Alla andra webbläsare lade till det också. Gecko var den enda webbläsaren vid den tiden som inte stödde den direkt i standardläge, utan valde istället att göra den till en experimentell funktion. Det var tvekan om att implementera det alls, men det gick vidare i namnet webbläsarkompatibilitet (Gecko försökte till och med övertyga WebKit för att flytta den ur standardläge) och så småningom kom den till standardläge i Firefox 14.

En sak som kanske inte är välkänd är att webbläsare var tvungna att vidta några försiktighetsåtgärder – med varierande grad av framgång – för att säkerställa att genererade globaler inte bryter webbsidan. En sådan åtgärd är...

Variabel skuggning

Den förmodligen mest intressanta delen av den här funktionen är att namngivna elementreferenser inte gör det skugga befintliga globala variabler. Så, om ett DOM-element har en id som redan är definierad som en global, kommer den inte att åsidosätta den befintliga. Till exempel:


  
    window.foo = "bar";
  


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

Och motsatsen är också sant:

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

Detta beteende är viktigt eftersom det upphäver farliga åsidosättanden som t.ex

, vilket annars skulle skapa en konflikt genom att ogiltigförklara alert API. Denna skyddsteknik kan mycket väl vara anledningen till att du - om du är som jag - lär dig om detta för första gången.

Fallet mot namngivna globaler

Tidigare sa jag att det kanske inte är den bästa idén att använda globala namngivna element som referenser. Det finns många anledningar till det, vilket TJ VanToll har täckt fint över på sin blogg och jag ska sammanfatta här:

  • Om DOM ändras, så gör referensen det också. Det gör några riktigt "spröda" (specens term för det) kod där separationen av problem mellan HTML och JavaScript kan vara för mycket.
  • Oavsiktliga referenser är alldeles för lätta. Ett enkelt stavfel kan mycket väl sluta hänvisa till en namngiven global och ge dig oväntade resultat.
  • Det implementeras annorlunda i webbläsare. Till exempel ska vi kunna komma åt ett ankare med en id - t.ex — men vissa webbläsare (nämligen Safari och Firefox) returnerar en ReferenceError i konsolen.
  • Det kanske inte returnerar vad du tror. Enligt specifikationen, när det finns flera instanser av samma namngivna element i DOM - säg två instanser av

    — webbläsaren ska returnera en HTMLCollection med en rad instanser. Firefox returnerar dock bara den första instansen. Sedan igen, specen säger vi borde använda en instans av en id i ett elements träd ändå. Men att göra det hindrar inte en sida från att fungera eller något liknande.

  • Kanske finns det en prestationskostnad? Jag menar, webbläsaren måste göra den listan med referenser och underhålla den. Ett par personer körde tester i denna StackOverflow-tråd, där namngivna globaler faktiskt fanns mer presterande i ett test och mindre presterande i ett nyare test.

Ytterligare överväganden

Låt oss säga att vi kastar bort kritiken mot att använda namngivna globaler och använder dem ändå. Allt är bra. Men det finns några saker du kanske vill tänka på när du gör.

Polyfills

Hur extremt det än kan låta är dessa typer av globala kontroller ett typiskt installationskrav för polyfills. Kolla in följande exempel där vi sätter en cookie med den nya CookieStore API, polyfilling det i webbläsare som inte stöder det ännu:


  
  
    // 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");
  

Den här koden fungerar perfekt i Chrome, men ger följande fel i Safari.:

TypeError: cookieStore.set is not a function

Safari saknar stöd för CookieStore API när detta skrivs. Som ett resultat appliceras inte polyfillen eftersom img element-ID skapar en global variabel som krockar med cookieStore global.

JavaScript API-uppdateringar

Vi kan vända på situationen och hitta ännu ett problem där uppdateringar av webbläsarens JavaScript-motor kan bryta ett namngivet elements globala referenser.

Till exempel:


  
  
    window.BarcodeDetector.focus();
  

Det skriptet tar en referens till indataelementet och anropar focus() på det. Det fungerar korrekt. Ändå vet vi inte hur lång det kommer att fortsätta att fungera.

Du förstår, den globala variabeln vi använder för att referera till inmatningselementet kommer att sluta fungera så snart webbläsare börjar stödja BarcodeDetector API. Vid den tidpunkten window.BarcodeDetector global kommer inte längre att vara en referens till indataelementet och .focus() kommer att kasta en "window.BarcodeDetector.focus är inte en funktion”-fel.

Bonus: Alla namngivna element genererar inte globala referenser

Vill du höra något roligt? För att lägga förolämpning till skadan är namngivna element tillgängliga som globala variabler endast om namnen inte innehåller annat än bokstav. Webbläsare skapar inte en global referens för ett element med ett ID som innehåller specialtecken och siffror, till exempel hello-world och item1.

Slutsats

Låt oss sammanfatta hur vi kom hit:

  • Alla större webbläsare skapar automatiskt globala referenser till varje DOM-element med en id (eller, i vissa fall, a name attribut).
  • Att komma åt dessa element genom deras globala referenser är opålitligt och potentiellt farligt. Använda sig av querySelector or getElementById istället.
  • Eftersom globala referenser genereras automatiskt kan de ha vissa biverkningar på din kod. Det är en bra anledning att undvika att använda id attribut om du inte verkligen behöver det.

I slutet av dagen är det förmodligen en bra idé att undvika att använda namngivna globaler i JavaScript. Jag citerade specifikationen tidigare om hur den leder till "skör" kod, men här är hela texten för att driva poängen hem:

Som en allmän regel kommer att förlita sig på detta leda till skör kod. Vilka ID:n som slutar mappa till detta API kan variera över tiden, eftersom nya funktioner till exempel läggs till webbplattformen. Använd istället för detta document.getElementById() or document.querySelector().

Jag tror att det faktum att HTML-specifikationen i sig rekommenderar att man håller sig borta från den här funktionen talar för sig själv.

Tidsstämpel:

Mer från CSS-tricks