Чи елементи дерева DOM з ідентифікаторами стають глобальними змінними?


364

Працюючи над ідеєю простої обгортки HTMLElement, я натрапив на наступне для Internet Explorer та Chrome :

Для даного HTMLElement з ідентифікатором у дереві 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методу в цих браузерах?



1
@Bergi, коментар, в якому йдеться про те, щоб цього не робити, тепер він застарів і навіть недійсний. Тому я не можу знайти конкретної причини не використовувати цю функцію.
ESR

@EdmundReed Ви можете прочитати відповідь на пов'язане питання ще раз - це все-таки погана ідея: " неявно оголошені глобальні змінні " мають погану відсутність підтримки інструментів та " призводять до крихкого коду ". Не називайте це "функцією", відповідь нижче пояснює, як це просто помилка, яка стала частиною стандарту з міркувань сумісності.
Бергі

1
@Bergi справедливо, ти маєш рацію. Я все ще думаю, що це дійсно акуратна особливість, і це вважається проблематичним лише тому, що люди цього не знають. Ось як я маю на увазі
ESR

@EdmundReed Менш проблематично, якщо ви, звичайно, не правильно розділяєте вміст та логіку. Також я рекомендую ніколи не використовувати оброблювачів вбудованих подій або встановлювати власні методи на елементи DOM, зловживаючи ними як простори імен (зауважте, це не "область").
Бергі

Відповіді:


395

Що повинно відбутися, це те, що "названі елементи" додаються як видимі властивості documentоб'єкта. Це дійсно погана ідея, оскільки дозволяє назви елементів зіткнутися з реальними властивостями document.

IE погіршив ситуацію, додавши також названі елементи як властивості windowоб'єкта. Це вдвічі погано в тому, що тепер ви повинні уникати називати свої елементи після того, як будь-який член documentабо windowоб'єкта, який ви (або будь-який інший код бібліотеки у вашому проекті) може використовувати.

Це також означає, що ці елементи видно як глобальні змінні. На щастя, будь-який реальний глобальний varабо functionдекларації у вашому коді затіняють їх, тому вам не потрібно так сильно хвилюватися про іменування тут, але якщо ви спробуєте виконати призначення глобальної змінної зі збіжним іменем, і ви забудете оголосити це var, ви отримаєте помилку в IE, оскільки він намагається призначити значення самому елементу.

Загалом вважається поганою практикою пропускати var, а також покладатися на те, що названі елементи можуть бути видимими на windowглобальних землях або як у них. Дотримуйтесь document.getElementById, що є більш широко підтримуваним і менш неоднозначним. Ви можете написати тривіальну функцію обгортки зі скороченою назвою, якщо вам не подобається введення тексту. Так чи інакше, немає сенсу використовувати кеш-код пошуку id-to-element, оскільки браузери, як правило, оптимізують getElementByIdвиклик для швидкого пошуку в будь-якому випадку; все, що ви отримуєте, - це проблеми, коли елементи змінюються idабо додаються / видаляються з документа.

Opera скопійована IE, а потім WebKit приєднався, і тепер як раніше нестандартизованное практика здачі названих елементів на documentвластивості, і раніше IE тільки практика здачі їх windowбудуть бути стандартизовані по HTML5, чий підхід до документа і стандартизувати кожен жахлива практика, яку наносили на нас автори браузерів, роблячи їх назавжди частиною Інтернету. Тож Firefox 4 також підтримуватиме це.

Що таке "названі елементи"? Все, що має id, і все, nameщо використовується, що використовується для "ідентифікації" цілей: тобто форми, зображення, якорі та деякі інші, але не інші непов'язані екземпляри nameатрибута, наприклад, назви контролів у полях введення форми, назви параметрів у <param>або тип метаданих у <meta>. "Ідентифікаційні" name- це ті, яких слід уникати на користь id.


5
Це чітка відповідь, дякую. Це було не моєю ідеєю опускати document.getElementById (ну, власне, я використовую xpath, де це можливо для пошуку елементів / елементів властивостей на сьогодні). Я натрапив на цю (погану) практику щодо названих предметів і мені було цікаво, звідки вона походить. Ви відповіли, що достатньо; тепер ми знаємо, чому його також можна знайти в Chrome (webkit).
KooiInc

18
Один виняток із "використання name слід уникати" - це те <input>, де nameатрибут відіграє вирішальну роль у формуванні ключа пар ключових значень для подання форми.
Яхель

7
FYI Firefox робить це лише в режимі примх.
Півмісяць Свіжий

4
@yahelc: саме таку різницю я роблю. "Не інші види використанняname зразок імен керування у полях введення форми ..."
bobince

13
ЧОМУ !? Чи можемо щось зробити, щоб зупинити це безумство? Мої функції переосмислювались посиланнями на елементи, і мені знадобилася година налагодження. :(
Farzher

52

Як було сказано у попередній відповіді, така поведінка відома як названий доступ до об'єкта вікна . Значення nameатрибута для деяких елементів і значення idатрибута для всіх елементів стають доступними як властивості глобального windowоб'єкта. Вони відомі як названі елементи. Оскільки windowв браузері є глобальний об'єкт, кожен названий елемент буде доступний як глобальна змінна.

Спочатку це було додано Internet Explorer і згодом було реалізовано всіма іншими браузерами просто для сумісності з сайтами, які залежать від такої поведінки. Цікаво, що Gecko (рендеринг Firefox) вирішив реалізувати це лише в режимі хитрощів , тоді як інші двигуни візуалізації залишали його в стандартному режимі.

Однак, як і для Firefox 14, Firefox тепер підтримує іменований доступ до windowоб'єкта в стандартному режимі. Чому вони змінили це? Виявляється, існує ще багато сайтів, які покладаються на цю функціональність у стандартному режимі. Microsoft навіть випустила маркетингову демонстрацію, яка це зробила, не даючи демонстрації працювати у Firefox.

Нещодавно Webkit вважає навпаки , переносячи іменований доступ на windowоб'єкт лише до режиму диваків. Вони вирішили проти цього тим же міркуванням, що і Гекко.

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

Чому? Про цю причину можна підсумувати багато міркувань про те, чому глобальні змінні погані . Простіше кажучи, наявність ще декількох додаткових глобальних змінних призводить до більшої кількості помилок. Скажімо, ви випадково введете ім’я a varі трапиться набрати idвузол DOM, SURPRISE!

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

  • IE неправильно робить значення nameатрибута доступним для елементів форми (введення, вибору тощо).
  • 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/ .


3
Лише зауваження до очевидного застереження до того, що "його не слід використовувати". Тобто, "це не повинно бути використане, якщо ви не ковбой коду". Ковбої коду просто йдуть на це.
Джеремі Фостер

5
@jeremyfoster, якщо "ковбой коду" означає того, хто використовує та поширює погані недобросовісні програми для розробників, я категорично не згоден.
Патрік Робертс

2
Один знак хорошого ковбоя полягає в тому, що багато хто не погоджується. Але зараз я як філософський ковбой чи щось подібне.
Джеремі Фостер

Більше людей повинні використовувати document.querySelectorAllта document.querySelectorотримувати доступ до DOM. +1 за гарну пропозицію використовувати це. Доступ до елементів селектором, безумовно, є більш ефективним процесом.
Travis J

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


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

1

Питання повинно звучати :: "Чи HTML-теги з наданими ідентифікаторами стають глобально доступними елементами DOM?"

Відповідь ТАК!

Ось як це було призначено для роботи, і саме тому W3C вводив ідентифікатори для початку: Ідентифікатор HTML-тегу в проаналізованому середовищі сценаріїв стає його відповідною ручкою елемента DOM Element.

Однак, Netscape Mozilla відмовився відповідати (натрапляючим на них) W3C і вперто продовжував використовувати застарілий атрибут Name для створення хаосу і, таким чином, порушував функцію Scripting та зручність кодування, що принесла введення W3C унікальних ідентифікаторів.

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

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

Їм легко вдалося переконати - тоді ще - переважаючу армію неосвічених любителів написання коду, що Імена та ідентифікатори практично однакові, за винятком того, що атрибут ID коротший і, отже, збереження байтів і зручніший для кодера, ніж властивість древнього Імені. Що було, звичайно, брехнею. Або - у замінених опублікованих статтях HTML, переконливих статтях, що вам потрібно буде вказати і ім’я, і ідентифікатор, щоб ваші теги були доступними для двигуна сценаріїв.

Мозаїчні вбивці [з кодовою назвою "Mozilla"] були настільки розлючені, що думали, "якщо ми підемо вниз, так повинен і Інтернет".

Майкрософт, що зростає, настільки наївний, що вважав, що він повинен зберігати застаріле і позначене для вилучення властивість Name і ставитися до нього так, ніби це ідентифікатор, який є унікальним ідентифікатором, щоб вони не порушили функціонал сценаріїв старі сторінки, кодовані стажистами Netscape. Вони були смертельно помиляються ...

І повернення колекції масиву елементів, що суперечать ідентифікаторам, також не було вирішенням цієї навмисної техногенної проблеми. Насправді це перемогло всю мету.

І це єдина причина, чому W3C виявився некрасивим і подарував нам такі ідіоти, як document.getElementByIdі супровідний рококо проклятий набридливий синтаксис подібного роду ... (...)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.