Nazwane identyfikatory elementów mogą być przywoływane jako JavaScript Globals PlatoBlockchain Data Intelligence. Wyszukiwanie pionowe. AI.

Nazwane identyfikatory elementów mogą być przywoływane jako globalne elementy JavaScript

Czy wiesz, że elementy DOM z identyfikatorami są dostępne w JavaScript jako zmienne globalne? To jedna z tych rzeczy, które istnieją od zawsze, ale naprawdę zagłębiam się w to po raz pierwszy.

Jeśli słyszysz o tym po raz pierwszy, przygotuj się! Możemy to zobaczyć w akcji po prostu dodając identyfikator do elementu w HTML:

Normalnie zdefiniujemy nową zmienną za pomocą querySelector("#cool") or getElementById("cool") aby wybrać ten element:

var el = querySelector("#cool");

Ale tak naprawdę już mamy dostęp do #cool bez tego rigamorale:

Więc każdy id - lub name atrybut, o to chodzi — w HTML można uzyskać dostęp w JavaScript za pomocą window[ELEMENT_ID]. Ponownie, nie jest to dokładnie „nowe”, ale naprawdę rzadko można to zobaczyć.

Jak można się domyślić, dostęp do zakresu globalnego z nazwanymi referencjami nie jest najlepszym pomysłem. Niektórzy ludzie zaczęli nazywać to „zanieczyszczającym zasięgiem globalnym”. Dowiemy się, dlaczego tak jest, ale najpierw…

Jakiś kontekst

Takie podejście jest opisane w specyfikacji HTML, gdzie jest opisany jako „dostęp nazwany na Window obiekt."

Internet Explorer jako pierwszy zaimplementował tę funkcję. Wszystkie inne przeglądarki również go dodały. Gecko było jedyną przeglądarką w tym czasie, która nie wspierała go bezpośrednio w trybie standardów, zamiast tego zdecydowała się uczynić z niego funkcję eksperymentalną. Były wahania, czy to w ogóle wdrożyć, ale to ruszył naprzód w imię kompatybilności z przeglądarką (Gekko nawet próbowało przekonać WebKit przenieść go z trybu standardów) i ostatecznie przeszedł do trybu standardów w Firefoksie 14.

Jedną rzeczą, która może nie być dobrze znana, jest to, że przeglądarki musiały zastosować kilka środków ostrożności — z różnym skutkiem — aby zapewnić, że wygenerowane globalne nie psują strony internetowej. Jednym z takich środków jest…

Zmienne cieniowanie

Prawdopodobnie najciekawszą częścią tej funkcji jest to, że odwołania do nazwanych elementów nie cień istniejące zmienne globalne. Tak więc, jeśli element DOM ma id który jest już zdefiniowany jako globalny, nie zastąpi istniejącego. Na przykład:


  
    window.foo = "bar";
  


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

Prawdą jest również coś przeciwnego:

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

To zachowanie jest niezbędne, ponieważ unieważnia niebezpieczne nadpisania, takie jak

, co w przeciwnym razie wywołałoby konflikt, unieważniając alert API. Ta technika zabezpieczania może być powodem, dla którego – jeśli jesteś taki jak ja – uczysz się o tym po raz pierwszy.

Sprawa przeciwko nazwanym globalom

Wcześniej powiedziałem, że używanie globalnych nazwanych elementów jako referencji może nie być najlepszym pomysłem. Jest wiele powodów, które TJ VanToll ładnie opisał na swoim blogu i tutaj podsumuję:

  • Jeśli DOM ulegnie zmianie, zmieni się również odwołanie. To sprawia, że ​​niektóre są naprawdę „kruche” (termin specyfikacji za to) kod, w którym rozdzielenie problemów między HTML i JavaScript może być zbyt duże.
  • Przypadkowe odniesienia są zbyt łatwe. Prosta literówka może równie dobrze skończyć się odwoływaniem się do nazwanej globalnej i dać nieoczekiwane wyniki.
  • Jest zaimplementowany inaczej w przeglądarkach. Na przykład powinniśmy mieć dostęp do kotwicy za pomocą id - np — ale niektóre przeglądarki (konkretnie Safari i Firefox) zwracają a ReferenceError w konsoli.
  • Może nie zwrócić tego, co myślisz. Zgodnie ze specyfikacją, gdy istnieje wiele wystąpień tego samego nazwanego elementu w DOM — powiedzmy, dwa wystąpienia

    — przeglądarka powinna zwrócić an HTMLCollection z tablicą instancji. Firefox zwraca jednak tylko pierwszą instancję. Potem znowu, specyfikacja mówi powinniśmy użyć jednego wystąpienia an id w drzewie elementu. Ale zrobienie tego nie zatrzyma działania strony ani niczego w tym rodzaju.

  • Może jest koszt wydajności? Chodzi mi o to, że przeglądarka musi stworzyć listę referencji i utrzymywać ją. Kilka osób przeprowadziło testy w tym wątku StackOverflow, gdzie właściwie były nazwane globale większa wydajność w jednym teście i mniej wydajny w nowszym teście.

Dodatkowe uwagi

Powiedzmy, że odrzucamy krytykę używania nazwanych globalnych i używamy ich mimo to. Wszystko jest dobrze. Ale jest kilka rzeczy, które możesz chcieć wziąć pod uwagę.

Wypełnienia

Choć może to zabrzmieć wyjątkowo, tego typu globalne sprawdzenia są typowym wymogiem konfiguracyjnym dla wypełniaczy. Sprawdź poniższy przykład, w którym ustawiamy plik cookie za pomocą nowego CookieStore API, wypełniając go ponownie w przeglądarkach, które jeszcze go nie obsługują:


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

Ten kod działa doskonale w Chrome, ale w Safari generuje następujący błąd:

TypeError: cookieStore.set is not a function

Safari nie obsługuje CookieStore API w chwili pisania tego tekstu. W rezultacie wypełnienie nie jest stosowane, ponieważ img ID elementu tworzy zmienną globalną, która koliduje z cookieStore światowy.

Aktualizacje API JavaScript

Możemy odwrócić sytuację i znaleźć kolejny problem, w którym aktualizacje silnika JavaScript przeglądarki mogą uszkodzić globalne odniesienia do nazwanego elementu.

Na przykład:


  
  
    window.BarcodeDetector.focus();
  

Ten skrypt pobiera odniesienie do elementu wejściowego i wywołuje focus() na tym. Działa poprawnie. Nadal nie wiemy jak długie będzie nadal działać.

Widzisz, zmienna globalna, której używamy do odwoływania się do elementu wejściowego, przestanie działać, gdy tylko przeglądarki zaczną obsługiwać BarcodeDetector API. W tym momencie window.BarcodeDetector global nie będzie już odwołaniem do elementu input i .focus() rzuci „window.BarcodeDetector.focus nie jest funkcją”.

Bonus: Nie wszystkie nazwane elementy generują globalne referencje

Chcesz usłyszeć coś zabawnego? Aby dodać obrazę do obrażeń, nazwane elementy są dostępne jako zmienne globalne tylko wtedy, gdy nazwy zawierają tylko literę. Przeglądarki nie utworzą globalnego odniesienia do elementu o identyfikatorze zawierającym znaki specjalne i cyfry, np. hello-world i item1.

Wnioski

Podsumujmy, jak tu dotarliśmy:

  • Wszystkie główne przeglądarki automatycznie tworzą globalne odniesienia do każdego elementu DOM za pomocą id (lub, w niektórych przypadkach, name atrybut).
  • Dostęp do tych elementów poprzez ich globalne odniesienia jest niewiarygodny i potencjalnie niebezpieczny. Posługiwać się querySelector or getElementById zamiast.
  • Ponieważ odwołania globalne są generowane automatycznie, mogą mieć pewne skutki uboczne w kodzie. To dobry powód, aby unikać używania id atrybut, chyba że naprawdę tego potrzebujesz.

Pod koniec dnia, prawdopodobnie dobrym pomysłem jest unikanie używania nazwanych globalnych w JavaScript. Cytowałem wcześniej specyfikację na temat tego, jak prowadzi to do „kruchego” kodu, ale oto pełny tekst, który ma na celu przybliżyć punkt:

Zasadniczo poleganie na tym prowadzi do kruchego kodu. To, które identyfikatory zostaną zmapowane do tego interfejsu API, mogą się zmieniać w czasie, na przykład w miarę dodawania nowych funkcji do platformy internetowej. Zamiast tego użyj document.getElementById() or document.querySelector().

Myślę, że sam fakt, że specyfikacja HTML zaleca trzymanie się z dala od tej funkcji, mówi sam za siebie.

Znak czasu:

Więcej z Sztuczki CSS