На ідентифікатори іменованих елементів можна посилатися як на JavaScript Globals PlatoBlockchain Data Intelligence. Вертикальний пошук. Ai.

На ідентифікатори іменованих елементів можна посилатися як на глобальні JavaScript

Чи знаєте ви, що елементи DOM з ідентифікаторами доступні в JavaScript як глобальні змінні? Це одна з тих речей, які були навколо, начебто, вічно, але я справді копаюся в цьому вперше.

Якщо ви вперше про це чуєте, будьте готові! Ми можемо побачити це в дії, просто додавши ідентифікатор до елемента в HTML:

Зазвичай ми визначаємо нову змінну за допомогою querySelector("#cool") or getElementById("cool") щоб вибрати цей елемент:

var el = querySelector("#cool");

Але ми фактично вже маємо доступ #cool без цієї моралі:

Отже, будь-який id - або name якщо на те пішло — у HTML можна отримати доступ у JavaScript за допомогою window[ELEMENT_ID]. Знову ж таки, це не зовсім «нове», але це справді рідко можна побачити.

Як ви можете здогадатися, доступ до глобальної області за допомогою іменованих посилань — не найкраща ідея. Деякі люди називають це «забруднювачем глобального масштабу». Ми розберемося, чому це так, але спочатку…

Якийсь контекст

Такий підхід є викладено в специфікації HTML, де це описано як «іменований доступ до Window об'єкт».

Internet Explorer був першим, хто реалізував цю функцію. Усі інші браузери також додали його. Gecko був єдиним браузером на той час, який не підтримував його безпосередньо в стандартному режимі, замість цього вирішив зробити це експериментальною функцією. Були вагання щодо його реалізації взагалі, але воно просунувся вперед у сумісності браузерів (Гекко навіть намагався переконати WebKit щоб вивести його зі стандартного режиму) і зрештою перейшов у стандартний режим у Firefox 14.

Одна річ, яка може бути не дуже відома, полягає в тому, що браузерам довелося застосувати кілька запобіжних заходів — із різним ступенем успіху — щоб гарантувати, що згенеровані глобали не зламатимуть веб-сторінку. Одним із таких заходів є…

Змінна тінь

Ймовірно, найцікавіша частина цієї функції полягає в тому, що посилання на іменовані елементи цього не роблять затіняти існуючі глобальні змінні. Отже, якщо елемент DOM має id який уже визначено як глобальний, він не замінить існуючий. Наприклад:


  
    window.foo = "bar";
  


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

І навпаки:

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

Така поведінка є важливою, оскільки вона скасовує небезпечні перевизначення, такі як

, що інакше призвело б до конфлікту через анулювання alert API. Ця техніка захисту цілком може бути причиною того, чому ви — якщо ви схожі на мене — дізнаєтеся про це вперше.

Справа проти названих глобалів

Раніше я казав, що використання глобальних іменованих елементів як посилань може бути не найкращою ідеєю. На це є багато причин, які TJ VanToll добре висвітлив у своєму блозі і я резюмую тут:

  • Якщо змінюється DOM, змінюється і посилання. Це робить деякі справді «крихкими» (термін спец для нього) код, де поділ проблем між HTML і JavaScript може бути занадто великим.
  • Випадкові посилання надто легкі. Проста друкарська помилка цілком може призвести до посилання на названий глобал і дати вам несподівані результати.
  • У браузерах це реалізовано інакше. Наприклад, ми повинні мати доступ до прив’язки за допомогою id — напр — але деякі браузери (а саме Safari та Firefox) повертають a ReferenceError в консолі.
  • Це може не повернути те, що ви думаєте. Відповідно до специфікації, якщо в DOM є кілька екземплярів одного і того ж іменованого елемента, скажімо, два екземпляри

    — браузер має повернути an HTMLCollection з масивом екземплярів. Однак Firefox повертає лише перший екземпляр. Потім знову, специфікація каже ми повинні використовувати один екземпляр an id у будь-якому випадку в дереві елементів. Але це не зупинить роботу сторінки чи щось подібне.

  • Можливо, є вартість продуктивності? Я маю на увазі, що браузер повинен створити цей список посилань і підтримувати його. Кілька людей провели тести у цьому потоці StackOverflow, де насправді були названі глобали більш ефективний в одному тесті та менш ефективний у нещодавньому тесті.

Додаткові міркування

Скажімо, ми відкинемо критику щодо використання іменованих глобалів і все одно використаємо їх. Це все добре. Але є деякі речі, які ви можете враховувати під час цього.

Поліфіли

Як би нестандартно це звучало, ці типи глобальних перевірок є типовою вимогою до налаштування полізаповнення. Перегляньте наведений нижче приклад, де ми встановлюємо файл cookie за допомогою new CookieStore API, заповнюючи його в браузерах, які ще не підтримують його:


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

Цей код чудово працює в Chrome, але видає таку помилку в Safari:

TypeError: cookieStore.set is not a function

Safari не підтримує CookieStore API на момент написання цієї статті. В результаті поліфіл не застосовується, тому що img Ідентифікатор елемента створює глобальну змінну, яка конфліктує з cookieStore глобальний

Оновлення JavaScript API

Ми можемо перевернути ситуацію та знайти ще одну проблему, коли оновлення двигуна JavaScript браузера можуть порушити глобальні посилання іменованого елемента.

Наприклад:


  
  
    window.BarcodeDetector.focus();
  

Цей сценарій захоплює посилання на вхідний елемент і викликає focus() на ньому. Він працює правильно. Все одно ми не знаємо як довго він продовжуватиме працювати.

Розумієте, глобальна змінна, яку ми використовуємо для посилання на елемент введення, перестане працювати, щойно браузери почнуть підтримувати BarcodeDetector API. У той момент, window.BarcodeDetector global більше не буде посиланням на елемент input і .focus() кине "window.BarcodeDetector.focus не є функцією».

Бонус: не всі іменовані елементи створюють глобальні посилання

Хочете почути щось смішне? Щоб додати образи до травми, іменовані елементи доступні як глобальні змінні, лише якщо імена містять лише букви. Браузери не створюватимуть глобальне посилання для елемента з ідентифікатором, який містить спеціальні символи та цифри, наприклад hello-world та item1.

Висновок

Давайте підсумуємо, як ми сюди потрапили:

  • Усі основні браузери автоматично створюють глобальні посилання на кожен елемент DOM за допомогою id (або, в деяких випадках, a name атрибут).
  • Доступ до цих елементів через їхні глобальні посилання є ненадійним і потенційно небезпечним. використання querySelector or getElementById замість цього.
  • Оскільки глобальні посилання генеруються автоматично, вони можуть мати деякі побічні ефекти на ваш код. Це вагомий привід уникати використання id атрибут, якщо він вам дійсно не потрібен.

Зрештою, ймовірно, доцільно уникати використання іменованих глобалів у JavaScript. Раніше я процитував специфікацію про те, як це призводить до «крихкого» коду, але ось повний текст, щоб підкреслити цю думку:

Як правило, покладаючись на це, код буде крихким. Ідентифікатори, які в кінцевому підсумку зіставляються з цим API, можуть змінюватися з часом, наприклад, коли до веб-платформи додаються нові функції. Замість цього використовуйте document.getElementById() or document.querySelector().

Я думаю, той факт, що сама специфікація HTML рекомендує триматися подалі від цієї функції, говорить сам за себе.

Часова мітка:

Більше від CSS-хитрощі