Становятся ли элементы дерева DOM с идентификаторами глобальными переменными?

364

Работая над идеей простой оболочки HTMLElement, я наткнулся на следующее для Internet Explorer и Chrome :

Для данного HTMLE-элемента с идентификатором в дереве DOM можно извлечь div, используя его идентификатор в качестве имени переменной. Так что для див как

<div id="example">some text</div>

в Internet Explorer 8 и Chrome вы можете сделать:

alert(example.innerHTML); //=> 'some text'

или

alert(window['example'].innerHTML); //=> 'some text'

Итак, означает ли это, что каждый элемент в дереве DOM преобразуется в переменную в глобальном пространстве имен? И это также означает, что можно использовать это в качестве замены для getElementByIdметода в этих браузерах?

KooiInc
источник
1
@ Берги, комментарий, в котором говорится, что не делать этого, теперь устарел и даже недействителен. Поэтому я не могу найти конкретную причину не использовать эту функцию.
ESR
@EdmundReed Возможно, вы захотите снова прочитать ответ на связанный вопрос - это все еще плохая идея: « неявно объявленные глобальные переменные » плохо работают с инструментами и « ведут к хрупкому коду ». Не называйте это «функцией», ответ ниже объясняет, почему это просто ошибка, которая стала частью стандарта по причинам совместимости.
Берги
1
@ Достаточно честно, ты прав. Я все еще думаю, что это действительно изящная функция, хотя и считается проблематичной, потому что люди не знают об этом. Вот как я это себе представляю: codepen.io/esr360/pen/WEavGE?editors=1000#0
ESR
@EdmundReed Это менее проблематично, если вы, конечно, не разделяете контент и логику должным образом. Также я рекомендую никогда не использовать встроенные обработчики событий или устанавливать собственные методы для элементов DOM, используя их как пространства имен (обратите внимание, что это не «область действия»).
Берги

Ответы:

395

Предполагается, что «именованные элементы» добавляются как видимые свойства documentобъекта. Это действительно плохая идея, так как она позволяет именам элементов конфликтовать с реальными свойствамиdocument .

IE усугубил ситуацию, добавив именованные элементы в качестве свойств windowобъекта. Это вдвойне плохо, так как теперь вы должны избегать именования ваших элементов после того, как любой из элементов documentили windowобъекта, который вы (или любой другой код библиотеки в вашем проекте) захотят использовать.

Это также означает, что эти элементы видны как глобальные переменные. К счастью, в этом случае любые реальные глобальные varили functionобъявления в вашем коде затеняют их, поэтому вам не нужно сильно беспокоиться об именовании здесь, но если вы попытаетесь сделать присвоение глобальной переменной с конфликтующим именем, и вы забудете объявить это var, вы получите ошибку в IE, поскольку он пытается присвоить значение самому элементу.

Обычно считается плохой практикой опускать var, а также полагаться на то, что именованные элементы видны windowили являются глобальными. Придерживайтесь document.getElementById, что более широко поддерживается и менее неоднозначно. Вы можете написать тривиальную функцию-обертку с более коротким именем, если вам не нравится печатать. В любом случае, нет смысла использовать кеш поиска идентификатора к элементу, потому что браузеры обычно оптимизируют getElementByIdвызов, чтобы в любом случае использовать быстрый поиск; все, что вы получаете, это проблемы, когда элементы изменяются idили добавляются / удаляются из документа.

Opera скопирована IE, а затем WebKit присоединилась, и теперь как ранее Нестандартизованные практики сдачи названных элементов на documentсвойствах, и ранее IE только практика сдачи их windowбудут быть стандартизирована по HTML5, чей подход к документу и стандартизировать каждый авторы браузеров навлекли на нас ужасную практику, сделав их навсегда частью сети. Так что Firefox 4 также будет поддерживать это.

Что такое «именованные элементы»? Все, что с id, и все, nameчто используется для «идентификации» целей: то есть формы, изображения, якоря и некоторые другие, но не другие не связанные экземпляры nameатрибута, такие как имена элементов управления в полях ввода формы, имена параметров в <param>или введите метаданные в <meta>. «Идентификации» nameследует избегать в пользу id.

bobince
источник
5
Это четкий ответ, спасибо. Моя идея не была опускать document.getElementById (ну, на самом деле, я использую xpath, где это возможно, чтобы искать элементы / свойства элементов в настоящее время). Я наткнулся на эту (плохую) практику для именованных предметов и мне было любопытно, откуда она взялась. Вы ответили на это достаточно тщательно; теперь мы знаем, почему его также можно найти в Chrome (webkit).
KooiInc
18
Единственное исключение из «использования nameследует избегать» - это случай <input>, когда nameатрибут играет критическую роль в формировании ключа пар ключ-значение для отправки формы.
Yahel
7
FYI Firefox делает это только в режиме причуд.
Crescent Fresh
4
@yahelc: это именно то различие, которое я делаю. «Не другое использование nameодинаковых управляющих имен в полях ввода формы ...»
bobince
13
ПОЧЕМУ!? Что мы можем сделать, чтобы остановить это безумие? Мои функции были переопределены ссылками на элементы, и отладка заняла у меня час. :(
Фаржер
52

Как упоминалось в предыдущем ответе, это поведение называется именованным доступом к объекту окна . Значение nameатрибута для некоторых элементов и значение idатрибута для всех элементов становятся доступными в качестве свойств глобального windowобъекта. Они известны как именованные элементы. Поскольку windowэто глобальный объект в браузере, каждый именованный элемент будет доступен как глобальная переменная.

Первоначально он был добавлен Internet Explorer и в конечном итоге был реализован всеми другими браузерами просто для совместимости с сайтами, которые зависят от этого поведения. Интересно, что Gecko (движок рендеринга Firefox) решил реализовать это только в режиме причуд , тогда как другие движки рендеринга оставили его включенным в стандартном режиме.

Однако, начиная с Firefox 14, Firefox теперь поддерживает именованный доступ к windowобъекту и в стандартном режиме. Почему они изменили это? Оказывается, есть еще много сайтов, которые используют эту функциональность в стандартном режиме. Microsoft даже выпустила маркетинговую демоверсию, которая не позволяла демоверсии работать в Firefox.

Недавно Webkit рассмотрел обратное , предоставив именованный доступ к windowобъекту только в режиме причуд. Они решили против этого по той же причине, что и Геккон.

Так что ... сумасшедший, поскольку кажется, что это поведение теперь технически безопасно использовать в последней версии всех основных браузеров в стандартном режиме . Но хотя именованный доступ может показаться несколько удобным, его не следует использовать .

Почему? В этой статье можно подвести итог многим рассуждениям о том, почему глобальные переменные плохие . Проще говоря, наличие множества дополнительных глобальных переменных приводит к большему количеству ошибок. Допустим, вы случайно набрали имя a varи случайно idнабрали узел DOM, СЮРПРИЗ!

Кроме того, несмотря на стандартизацию, в браузерных реализациях именованного доступа все еще остается довольно много несоответствий.

  • IE неправильно делает значение nameатрибута доступным для элементов формы (input, select и т. Д.).
  • Gecko и Webkit неправильно НЕ делают <a>теги доступными через их nameатрибут.
  • Gecko неправильно обрабатывает несколько именованных элементов с одинаковыми именами (вместо массива ссылок возвращает ссылку на один узел).

И я уверен, что это еще не все, если вы попытаетесь использовать именованный доступ в крайних случаях.

Как уже упоминалось в других ответах, используйте document.getElementByIdдля получения ссылки на узел DOM id. Если вам нужно получить ссылку на узел по его nameатрибуту, используйте document.querySelectorAll.

Пожалуйста, не распространяйте эту проблему, используя именованный доступ на вашем сайте. Так много веб-разработчиков потратили впустую время, пытаясь отследить это волшебное поведение. Нам действительно нужно принять меры и заставить механизмы рендеринга отключить именованный доступ в стандартном режиме. В краткосрочной перспективе это приведет к тому, что некоторые сайты будут совершать плохие поступки, но в долгосрочной перспективе это поможет продвинуть сеть вперед.

Если вам интересно, я расскажу об этом более подробно в моем блоге - https://www.tjvantoll.com/2012/07/19/dom-element-references-as-global-variables/ .

TJ VanToll
источник
3
Просто примечание к очевидному предупреждению о том, что «его не следует использовать». То есть «его нельзя использовать, если вы не ковбой в коде». Кодовые ковбои просто идут на это.
Джереми Фостер
5
@jeremyfoster, если «кодовый ковбой» не означает кого-то, кто использует и распространяет плохие реализации, недружественные разработчикам, я категорически не согласен.
Патрик Робертс
2
Одним из признаков хорошего ковбоя является то, что многие не согласны. Но сейчас я как философский ковбой или что-то в этом роде.
Джереми Фостер
Больше людей должны использовать document.querySelectorAllи document.querySelectorпри доступе к DOM. +1 за хорошее предложение использовать это. Доступ к элементам с помощью селектора определенно является более эффективным процессом.
Трэвис Дж
20

Вы должны придерживаться getElementById()в этих случаях, например:

document.getElementById('example').innerHTML

IE любит смешивать элементы name и ID атрибуты в глобальном пространстве имен, поэтому лучше четко указывать, что вы пытаетесь получить.

Ник Крейвер
источник
3

Да, они делают.

Протестировано в Chrome 55, Firefox 50, IE 11, IE Edge 14 и Safari 10
на следующем примере:

<!DOCTYPE html>
<html>
<head>
</head>
<body>
  <div id="im_not_particularly_happy_with_that">
    Hello World!
  </div>
  <script>
    im_not_particularly_happy_with_that.innerText = 'Hello Internet!';
  </script>
  <!-- Looking at you W3 HTML5 spec group _ -->
</body>
</html>

http://jsbin.com/mahobinopa/edit?html,output

QFF
источник
1
Также в Опере. Тем не менее, я думаю, что возражения против этого механизма, изложенные на этой странице, очень хорошо приняты.
ncmathsadist
1

Должен прозвучать вопрос: «Становятся ли HTML-теги с предоставленными идентификаторами глобально доступными элементами DOM?»

Ответ ДА!

Вот как это должно было работать, и именно поэтому W3C начал вводить идентификаторы. Идентификатор тега HTML в проанализированной среде сценариев становится соответствующим дескриптором элемента DOM.

Тем не менее, Netscape Mozilla отказалась отвечать (на их вторгаясь) W и упорно продолжала использовать устаревшую атрибут Имени, чтобы создать хаос и, следовательно, разорвет функциональность сценариев и удобство кодирования, приносимое введением W3C в Уникальных идентификаторах.

После фиаско Netscape Navigator 4.7 все их разработчики пошли и проникли в W3C, в то время как их партнеры вытесняли Интернет неправильными методами и не использовали примеры. Принудительное использование и повторное использование уже устаревшего атрибута Name [!, Который не должен был быть уникальным] наравне с атрибутами ID, чтобы сценарии, использующие идентификаторы для доступа к определенным элементам DOM, просто ломались!

И перерыв они сделали , как они будут также писать и публиковать обширные кодирования уроков и примеры [их браузер не распознает все равно] , такие , как document.all.ElementID.propertyвместо того , ElementID.propertyчтобы по крайней мере , сделать его неэффективным и дать браузер более накладные расходы в случае , если это не просто разбить его на HTML-домен с использованием того же токена для имени (теперь [1996-97] устарело) и стандартного атрибута ID, предоставляющего ему такое же значение токена.

Им легко удалось убедить - тогдашнюю - подавляющую армию невежественных любителей написания кода в том, что имена и идентификаторы практически одинаковы, за исключением того, что атрибут идентификатора короче и, следовательно, сохраняет байты и более удобен для кодера, чем свойство древнего имени. Что, конечно, было ложью. Или - в их заменяющих опубликованных статьях HTML, убедительных статьях, что вам нужно будет указать и имя, и идентификатор для своих тегов, чтобы они были доступны для механизма сценариев.

Убийцы Мозаики (под кодовым названием «Мозилла») были настолько взбешены, что подумали: «Если мы пойдем вниз, то и Интернет тоже».

Растущая Microsoft - с другой стороны - была настолько наивна, что подумала, что должна оставить устаревшее и помеченное для удаления свойство Name и обращаться с ним так, как если бы это был идентификатор с уникальным идентификатором, чтобы они не нарушали функциональные возможности сценариев. старые страницы, закодированные стажерами Netscape. Они были смертельно неправы ...

И возвращение коллекции массивов элементов, конфликтующих с ID, также не было решением этой намеренной искусственной проблемы. На самом деле это победило всю цель.

И это единственная причина, по которой W3C стал уродливым и дал нам идиотизм, такой как document.getElementByIdи сопутствующий ему чертов раздражающий синтаксис в стиле рококо ... (...)

Беким Бакай
источник