Czy elementy drzewa DOM z identyfikatorami stają się zmiennymi globalnymi?

364

Pracując nad pomysłem na proste opakowanie HTMLElement natknąłem się na następujące dla Internet Explorera i Chrome :

Dla danego elementu HTMLElement z identyfikatorem w drzewie DOM można pobrać div, używając jego identyfikatora jako nazwy zmiennej. Więc jak div

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

w Internet Explorerze 8 i Chrome możesz:

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

lub

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

Czy to oznacza, że każdy element w drzewie DOM jest konwertowany na zmienną w globalnej przestrzeni nazw? Czy oznacza to również, że można tego użyć jako zamiennika getElementByIdmetody w tych przeglądarkach?

KooiInc
źródło
1
@Bergi, komentarz, który mówi, że tego nie robić, jest teraz nieaktualny, a nawet nieprawidłowy. Dlatego nie mogę znaleźć konkretnego powodu, aby nie korzystać z tej funkcji.
ESR
@EdmundReed Być może zechcesz ponownie przeczytać odpowiedź na połączone pytanie - to wciąż zły pomysł: „ niejawnie zadeklarowane zmienne globalne ” mają złe wsparcie dla narzędzi i „ prowadzą do łamliwego kodu ”. Nie nazywaj tego „funkcją”, odpowiedź poniżej wyjaśnia, że ​​to błąd, który stał się częścią standardu ze względu na kompatybilność.
Bergi,
1
@Bergi wystarczy, masz rację. Nadal uważam, że jest to naprawdę fajna funkcja i jest uważana za problematyczną, ponieważ ludzie nie są tego świadomi. Tak wyobrażam sobie użycie tego: codepen.io/esr360/pen/WEavGE?editors=1000#0
ESR
@EdmundReed To mniej problematyczne, jeśli nie oddzielisz odpowiednio treści i logiki. Polecam też nigdy nie używać wbudowanych programów obsługi zdarzeń ani instalować niestandardowych metod w elementach DOM, nadużywając ich jako przestrzeni nazw (zauważ, że nie jest to „zakres”).
Bergi,

Odpowiedzi:

395

To, co ma się zdarzyć, to dodanie nazwanych elementów jako widocznych właściwości documentobiektu. To naprawdę zły pomysł, ponieważ pozwala na konflikt nazw elementów z rzeczywistymi właściwościami document.

IE pogorszyło sytuację, dodając nazwane elementy jako właściwości windowobiektu. Jest to podwójnie złe, ponieważ teraz musisz unikać nazywania swoich elementów po dowolnym elemencie elementu documentlub windowobiektu, którego możesz chcieć użyć (lub innego kodu biblioteki w projekcie).

Oznacza to również, że elementy te są widoczne jako zmienne globalne. Na szczęście w tym przypadku wszelkie prawdziwe globalne varlub functiondeklaracje w twoim kodzie przesłaniają je, więc nie musisz się tak martwić o nazewnictwo tutaj, ale jeśli spróbujesz wykonać przypisanie do zmiennej globalnej o sprzecznej nazwie i zapomnisz zadeklarować to var, dostaniesz błąd w IE, ponieważ próbuje przypisać wartość samego elementu.

Powszechnie uważa się za złą praktykę pomijanie var, a także poleganie na tym, że nazwane elementy są widoczne na windowlub jako globale. Trzymaj się document.getElementById, który jest bardziej wspierany i mniej dwuznaczny. Możesz napisać trywialną funkcję otoki o krótszej nazwie, jeśli nie podoba ci się pisanie. Tak czy inaczej, nie ma sensu używać pamięci podręcznej wyszukiwania id-to-element, ponieważ przeglądarki zazwyczaj optymalizują getElementByIdpołączenie, aby i tak użyć szybkiego wyszukiwania; otrzymujesz tylko problemy, gdy elementy się zmieniają idlub są dodawane / usuwane z dokumentu.

Opera kopiowane IE, następnie WebKit dołączył, a teraz oba wcześniej unstandardised praktyka umieszczania nazwanych elementów na documentwłaściwości, a wcześniej-IE-only praktyka wprowadzanie ich window standaryzowane przez HTML5, którego podejście do dokumentu i ujednolicenia każdy okropna praktyka narzucona nam przez autorów przeglądarek, przez co stają się częścią sieci na zawsze. Tak więc Firefox 4 również to obsługuje.

Co to są „nazwane elementy”? Wszystko z idczymkolwiek i czymkolwiek nameużywanym do celów „identyfikacji”: to znaczy formularze, obrazy, kotwice i kilka innych, ale nie inne niepowiązane wystąpienia nameatrybutu, takie jak nazwy kontrolne w polach wejściowych formularza, nazwy parametrów w <param>lub wpisz metadane <meta>. Identyfikatory nameto takie, których należy unikać na korzyść id.

Bobin
źródło
5
To jasna odpowiedź, dzięki. Nie było moim pomysłem pominięcie document.getElementById (cóż, w rzeczywistości używam xpath tam, gdzie to możliwe, do wyszukiwania elementów / właściwości elementów). Natknąłem się na tę (złą) praktykę dla nazwanych przedmiotów i byłem ciekawy, skąd ona pochodzi. Odpowiedziałeś na to wystarczająco dokładnie; teraz wiemy, dlaczego można go również znaleźć w Chrome (webkit).
KooiInc
18
Jednym wyjątkiem od „ namenależy unikać używania ” jest <input>sytuacja, w której nameatrybut odgrywa kluczową rolę w tworzeniu klucza par klucz-wartość dla formularzy.
Yahel,
7
FYI Firefox robi to tylko w trybie dziwactwa.
Crescent Fresh
4
@yahelc: dokładnie to robię. „Nie inne zastosowania namepodobnych nazw kontrolnych w polach wprowadzania formularza ...”
Bob
13
DLACZEGO!? Czy jest coś, co możemy zrobić, aby powstrzymać to szaleństwo? Moje funkcje zostały ponownie zdefiniowane przez odwołania do elementów i debugowanie zajęło mi godzinę. :(
Farzher
52

Jak wspomniano we wcześniejszej odpowiedzi, takie zachowanie jest znane jako nazwany dostęp do obiektu okna . Wartość nameatrybutu dla niektórych elementów i wartość idatrybutu dla wszystkich elementów są udostępniane jako właściwości windowobiektu globalnego . Są to tak zwane elementy nazwane. Ponieważ windowjest to obiekt globalny w przeglądarce, każdy nazwany element będzie dostępny jako zmienna globalna.

Zostało to pierwotnie dodane przez Internet Explorera i ostatecznie zostało zaimplementowane przez wszystkie inne przeglądarki po prostu w celu zapewnienia zgodności z witrynami zależnymi od tego zachowania. Co ciekawe, Gecko (silnik renderujący Firefoksa) postanowił zaimplementować to tylko w trybie dziwactw , podczas gdy inne silniki renderujące pozostawiały go w trybie standardowym.

Jednak, jak Firefox 14, Firefox obsługuje teraz o nazwie dostępu na windowobiekcie w trybie standardowym, jak również. Dlaczego to zmienili? Okazuje się, że wciąż wiele witryn korzysta z tej funkcjonalności w trybie standardowym. Microsoft wydał nawet demo marketingowe, które tak zrobiło, uniemożliwiając jego działanie w Firefoksie.

Webkit ostatnio rozważałwindow coś przeciwnego , przenosząc nazwany dostęp do obiektu tylko do trybu dziwactwa. Zdecydowali się przeciw temu z tego samego powodu, co Gecko.

Więc… szalone, jak się wydaje, takie zachowanie jest teraz technicznie bezpieczne w najnowszej wersji wszystkich głównych przeglądarek w trybie standardowym . Ale chociaż nazwany dostęp może wydawać się nieco wygodny, nie należy go używać .

Dlaczego? Wiele argumentów można streścić w tym artykule na temat tego, dlaczego zmienne globalne są złe . Mówiąc najprościej, posiadanie szeregu dodatkowych zmiennych globalnych prowadzi do większej liczby błędów. Załóżmy, że przypadkowo wpisałeś nazwę a vari zdarzyło Ci się wpisać an idwęzła DOM, SURPRISE!

Ponadto, pomimo ujednolicenia, nadal istnieje sporo rozbieżności w implementacjach nazwanego dostępu do przeglądarki.

  • IE niepoprawnie udostępnia wartość nameatrybutu dla elementów formularza (input, select itp.).
  • Gecko i Webkit nieprawidłowo NIE udostępniają <a>tagów za pomocą ich nameatrybutu.
  • Gecko niepoprawnie obsługuje wiele nazwanych elementów o tej samej nazwie (zwraca odwołanie do pojedynczego węzła zamiast tablicy odniesień).

I jestem pewien, że jest więcej, jeśli spróbujesz użyć nazwanego dostępu w przypadkach na krawędzi.

Jak wspomniano w innych odpowiedziach, użyj, document.getElementByIdaby uzyskać odniesienie do węzła DOM przez jego id. Jeśli potrzebujesz uzyskać odwołanie do węzła, nameużyj jego atrybutu document.querySelectorAll.

Proszę nie rozpowszechniać tego problemu przy użyciu dostępu nazwanego w swojej witrynie. Tak wielu programistów internetowych zmarnowało czas, próbując wyśledzić to magiczne zachowanie. Naprawdę musimy podjąć działania i uzyskać silniki renderujące, aby wyłączyć dostęp nazwany w trybie standardów. W krótkim okresie spowoduje to uszkodzenie niektórych witryn, które robią złe rzeczy, ale na dłuższą metę pomoże to rozwinąć sieć.

Jeśli jesteś zainteresowany, mówię o tym bardziej szczegółowo na moim blogu - https://www.tjvantoll.com/2012/07/19/dom-element-references-as-global-variables/ .

TJ VanToll
źródło
3
Tylko uwaga na oczywiste zastrzeżenie do założenia, że ​​„nie należy go używać”. Oznacza to, że „nie należy go używać, chyba że jesteś kowbojem kodu”. Kowboje z kodem po prostu to robią.
Jeremy Foster
5
@jeremyfoster, chyba że „kowboj kodu” oznacza kogoś, kto używa i propaguje złe, nieprzyjazne dla programistów implementacje, zdecydowanie się nie zgadzam.
Patrick Roberts
2
Znakiem dobrego kowboja jest to, że wielu się nie zgadza. Ale teraz jestem jak filozoficzny kowboj czy coś takiego.
Jeremy Foster
Więcej osób powinno korzystać document.querySelectorAlli document.querySelectorpodczas uzyskiwania dostępu do DOM. +1 za dobrą sugestię użycia tego. Dostęp do elementów za pomocą selektora jest zdecydowanie bardziej wydajnym procesem.
Travis J
20

W getElementById()takich przypadkach powinieneś się trzymać , na przykład:

document.getElementById('example').innerHTML

IE lubi mieszać elementy name i ID atrybuty w globalnej przestrzeni nazw, więc najlepiej jest wyraźnie powiedzieć, co próbujesz uzyskać.

Nick Craver
źródło
3

Tak, robią.

Testowane w Chrome 55, Firefox 50, IE 11, IE Edge 14 i Safari 10
na następującym przykładzie:

<!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
źródło
1
Również w Operze. Myślę jednak, że sprzeciw wobec tego mechanizmu wyrażony na tej stronie jest bardzo dobrze przyjęty.
ncmathsadist
1

Pytanie powinno brzmieć: „Czy tagi HTML z podanymi identyfikatorami stają się globalnie dostępnymi elementami DOM?”

Odpowiedź brzmi tak!

Tak to miało działać i dlatego W3C na początku wprowadził identyfikatory: ID tagu HTML w przeanalizowanym środowisku skryptowym staje się odpowiadającym mu uchwytem elementu DOM.

Jednak Netscape Mozilla odmówił dostosowania się do (do nich intruzów) W3C i uparcie używał przestarzałego atrybutu Name, aby wywołać spustoszenie, a tym samym złamać funkcjonalność Skryptu i wygodę kodowania wprowadzoną przez wprowadzenie unikatowych identyfikatorów przez W3C.

Po fiasku Netscape Navigator 4.7 wszyscy programiści poszli i infiltrowali W3C, podczas gdy ich współpracownicy zastępowali Internet niewłaściwymi praktykami i niewłaściwymi przykładami. Wymuszenie użycia i ponownego użycia już nieaktualnego atrybutu Name [!, Który nie miał być unikalny] na równi z atrybutami ID, aby skrypty wykorzystujące uchwyty ID do uzyskiwania dostępu do poszczególnych elementów DOM po prostu się zepsuły!

I złamali to, co napisali i opublikowali obszerne lekcje kodowania i przykłady [ich przeglądarka i tak nie rozpoznaje], takie jak document.all.ElementID.propertyzamiast ElementID.propertyuczynić go co najmniej nieefektywnym i dać przeglądarce więcej narzutu, gdyby nie po prostu go złamał Domena HTML przy użyciu tego samego tokena dla (obecnie [1996-97], przestarzała) Nazwy i standardowego atrybutu ID dostarczającego tę samą wartość tokena.

Z łatwością udało im się przekonać - w tamtym czasie - przytłaczającą armię nieświadomych amatorów pisania kodu, że Nazwy i identyfikatory są praktycznie takie same, z tym wyjątkiem, że atrybut ID jest krótszy, a zatem oszczędzający bajty i wygodniejszy dla programisty niż starożytna właściwość Name. Co oczywiście było kłamstwem. Lub - w ich zastępujących opublikowanych artykułach HTML, przekonujących artykułach, że musisz podać zarówno nazwę, jak i identyfikator do swoich tagów, aby były dostępne dla silnika skryptów.

Mosaic Killers [o kryptonimie „Mozilla”] byli tak wkurzeni, że pomyśleli „jeśli zejdziemy na dół, to też Internet”.

Wschodzący Microsoft - z drugiej strony - był tak naiwny, że uważali, że powinni zachować przestarzałą i oznaczoną do usunięcia właściwość Name i traktować ją tak, jakby to był identyfikator, który jest unikalnym identyfikatorem, aby nie złamali funkcji skryptowej stare strony kodowane przez stażystów Netscape. Byli śmiertelnie w błędzie ...

Zwracanie kolekcji tablic elementów sprzecznych z ID nie było również rozwiązaniem tego umyślnego problemu stworzonego przez człowieka. W rzeczywistości pokonało to cały cel.

I to jest jedyny powód, dla którego W3C stała się brzydka i dała nam takie idioci, jak document.getElementByIdi towarzysząca jej rokoko cholerna irytująca składnia tego rodzaju ... (...)

Bekim Bacaj
źródło