Werden DOM-Baumelemente mit IDs zu globalen Variablen?

364

Als ich an einer Idee für einen einfachen HTMLElement-Wrapper arbeitete, stieß ich auf Folgendes für Internet Explorer und Chrome :

Für ein bestimmtes HTMLElement mit ID im DOM-Baum ist es möglich, das div unter Verwendung seiner ID als Variablennamen abzurufen. Also für einen Div wie

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

In Internet Explorer 8 und Chrome können Sie Folgendes tun:

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

oder

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

Bedeutet dies also, dass jedes Element im DOM-Baum in eine Variable im globalen Namespace konvertiert wird? Und heißt das auch, dass man dies als Ersatz für die getElementByIdMethode in diesen Browsern verwenden kann?

KooiInc
quelle
1
@Bergi, der Kommentar, der besagt, dies nicht zu tun, ist jetzt veraltet und sogar ungültig. Daher kann ich keinen konkreten Grund finden, diese Funktion nicht zu verwenden.
ESR
@EdmundReed Vielleicht möchten Sie die Antwort auf die verknüpfte Frage noch einmal lesen - es ist immer noch eine schlechte Idee: " implizit deklarierte globale Variablen " haben schlechte bis keine Werkzeugunterstützung und " führen zu sprödem Code ". Nennen Sie es nicht "Feature", die Antwort unten erklärt, wie es nur ein Fehler ist, der aus Kompatibilitätsgründen Teil des Standards wurde.
Bergi
1
@Bergi fair genug, du hast recht. Ich denke immer noch, dass es eine wirklich nette Funktion ist und nur als problematisch angesehen wird, weil die Leute sich dessen nicht bewusst sind. So stelle
ESR
@EdmundReed Es ist weniger problematisch, wenn Sie Inhalt und Logik natürlich nicht richtig trennen. Außerdem empfehle ich, niemals Inline-Ereignishandler zu verwenden oder benutzerdefinierte Methoden für DOM-Elemente zu installieren, die sie als Namespaces missbrauchen (beachten Sie, dass dies kein "Bereich" ist).
Bergi

Antworten:

395

Was passieren soll, ist, dass 'benannte Elemente' als scheinbare Eigenschaften des documentObjekts hinzugefügt werden. Dies ist eine wirklich schlechte Idee, da Elementnamen mit realen Eigenschaften von kollidieren könnendocument .

IE verschlimmerte die Situation, indem auch benannte Elemente als Eigenschaften des windowObjekts hinzugefügt wurden . Dies ist insofern doppelt schlecht, als Sie jetzt vermeiden müssen, Ihre Elemente nach einem Mitglied des documentoder des windowObjekts zu benennen, das Sie (oder ein anderer Bibliothekscode in Ihrem Projekt) möglicherweise verwenden möchten.

Dies bedeutet auch, dass diese Elemente als global ähnliche Variablen sichtbar sind. Glücklicherweise werden sie in diesem Fall von echten globalen Deklarationen varoder functionDeklarationen in Ihrem Code beschattet, sodass Sie sich hier nicht so viele Gedanken über die Benennung machen müssen. Wenn Sie jedoch versuchen, eine Zuordnung zu einer globalen Variablen mit einem zusammenstoßenden Namen vorzunehmen, und Sie vergessen, diese zu deklarieren In diesem varFall wird im IE eine Fehlermeldung angezeigt, wenn versucht wird, den Wert dem Element selbst zuzuweisen.

Es wird allgemein als schlechte Praxis angesehen, wegzulassen varund sich darauf zu verlassen, dass benannte Elemente auf windowoder als Globals sichtbar sind. Halten Sie sich an document.getElementById, was mehr unterstützt und weniger mehrdeutig ist. Sie können eine einfache Wrapper-Funktion mit einem kürzeren Namen schreiben, wenn Sie die Eingabe nicht mögen. In beiden Fällen macht es keinen Sinn, einen ID-zu-Element-Suchcache zu verwenden, da Browser den getElementByIdAufruf normalerweise so optimieren , dass ohnehin eine schnelle Suche verwendet wird. Alles, was Sie bekommen, sind Probleme, wenn Elemente geändert idoder dem Dokument hinzugefügt / daraus entfernt werden.

Opera hat den IE kopiert, dann hat WebKit mitgemacht, und jetzt werden sowohl die bisher nicht standardisierte Praxis, benannte Elemente auf documentEigenschaften zu setzen, als auch die bisher nur IE-Praxis, sie auf Eigenschaften zu windowsetzen , durch HTML5 standardisiert , dessen Ansatz darin besteht, alle zu dokumentieren und zu standardisieren schreckliche Praxis, die uns von Browser-Autoren auferlegt wurde und die sie für immer zum Teil des Webs macht. Firefox 4 wird dies also auch unterstützen.

Was sind "benannte Elemente"? Alles mit einem idund alles mit einem nameWesen, das zum 'Identifizieren' verwendet wird: Formulare, Bilder, Anker und einige andere, aber keine anderen nicht verwandten Instanzen eines nameAttributs, wie Kontrollnamen in Formulareingabefeldern, Parameternamen in <param>oder Metadaten eingeben <meta>. "Identifizieren" namesind diejenigen, die zugunsten von vermieden werden sollten id.

Bobince
quelle
5
Das ist eine klare Antwort, danke. Es war nicht meine Idee, document.getElementById wegzulassen (tatsächlich verwende ich heutzutage xpath, wo es möglich ist, um Elemente / Elementeigenschaften heutzutage nachzuschlagen). Ich bin auf diese (schlechte) Praxis für benannte Gegenstände gestoßen und war neugierig, woher sie kommt. Sie haben das gründlich genug beantwortet; Jetzt wissen wir, warum es auch in Chrome (Webkit) zu finden ist.
KooiInc
18
Eine Ausnahme von "Verwendung von namesollte vermieden werden" ist bei <input>, wo das nameAttribut eine entscheidende Rolle bei der Bildung des Schlüssels von Schlüssel-Wert-Paaren für Formularübermittlungen spielt.
Yahel
7
FYI Firefox tut dies nur, wenn es in den Mackenmodus versetzt wird.
Crescent Fresh
4
@yahelc: das ist genau die Unterscheidung, die ich mache. "Nicht andere Verwendungen von nameähnlichen Kontrollnamen in Formulareingabefeldern ..."
Bobince
13
WARUM!? Können wir irgendetwas tun, um diesen Wahnsinn zu stoppen? Meine Funktionen wurden durch Verweise auf Elemente neu definiert und das Debuggen dauerte eine Stunde. :(
Farzher
52

Wie in der vorherigen Antwort erwähnt, wird dieses Verhalten als benannter Zugriff auf das Fensterobjekt bezeichnet . Der Wert des nameAttributs für einige Elemente und der Wert des idAttributs für alle Elemente werden als Eigenschaften des globalen windowObjekts verfügbar gemacht . Diese werden als benannte Elemente bezeichnet. Da windowes sich um das globale Objekt im Browser handelt, kann auf jedes benannte Element als globale Variable zugegriffen werden.

Dies wurde ursprünglich von Internet Explorer hinzugefügt und schließlich von allen anderen Browsern implementiert, um die Kompatibilität mit Websites zu gewährleisten, die von diesem Verhalten abhängig sind. Interessanterweise hat sich Gecko (die Rendering-Engine von Firefox) dafür entschieden, dies nur im Mackenmodus zu implementieren , während andere Rendering-Engines es im Standardmodus aktiviert haben.

Ab Firefox 14 unterstützt Firefox jetzt auch den benannten Zugriff auf das windowObjekt im Standardmodus. Warum haben sie das geändert? Es stellt sich heraus, dass es immer noch viele Websites gibt, die im Standardmodus auf diese Funktionalität angewiesen sind. Microsoft hat sogar eine Marketing-Demo veröffentlicht , die verhindert, dass die Demo in Firefox funktioniert.

Webkit hat kürzlich das Gegenteil in Betracht gezogen und den benannten Zugriff auf das windowObjekt nur in den Mackenmodus versetzt. Sie entschieden sich aus denselben Gründen wie Gecko dagegen.

Also… verrückt, wie es scheint, ist dieses Verhalten jetzt technisch sicher in der neuesten Version aller gängigen Browser im Standardmodus zu verwenden . Der benannte Zugriff kann zwar etwas bequem erscheinen, sollte jedoch nicht verwendet werden .

Warum? In diesem Artikel lassen sich viele Gründe dafür zusammenfassen, warum globale Variablen schlecht sind . Einfach ausgedrückt, führt eine Reihe zusätzlicher globaler Variablen zu mehr Fehlern. Angenommen , Sie geben versehentlich den Namen von a ein varund geben zufällig einen idvon einem DOM-Knoten ein, SURPRISE!

Darüber hinaus gibt es trotz der Standardisierung immer noch einige Unstimmigkeiten bei der Implementierung des benannten Zugriffs durch den Browser.

  • IE macht den Wert des nameAttributs fälschlicherweise für Formularelemente zugänglich (Eingabe, Auswahl usw.).
  • Gecko und Webkit machen fälschlicherweise NICHT <a> Tags über ihr nameAttribut zugänglich .
  • Gecko behandelt mehrere benannte Elemente mit demselben Namen falsch (es gibt eine Referenz auf einen einzelnen Knoten anstelle eines Arrays von Referenzen zurück).

Und ich bin sicher, es gibt noch mehr, wenn Sie versuchen, benannten Zugriff auf Randfälle zu verwenden.

Wie in anderen Antworten erwähnt, wird verwendet document.getElementById, um eine Referenz auf einen DOM-Knoten durch dessen zu erhalten id. Wenn Sie anhand seines nameAttributs einen Verweis auf einen Knoten erhalten möchten, verwenden Sie document.querySelectorAll.

Bitte, bitte verbreiten Sie dieses Problem nicht, indem Sie den benannten Zugriff auf Ihrer Site verwenden. So viele Webentwickler haben Zeit damit verschwendet, dieses magische Verhalten aufzuspüren . Wir müssen wirklich Maßnahmen ergreifen und Rendering-Engines dazu bringen, den benannten Zugriff im Standardmodus zu deaktivieren. Kurzfristig wird es einige Websites beschädigen, die schlechte Dinge tun, aber auf lange Sicht wird es helfen, das Web voranzubringen.

Wenn Sie interessiert sind, spreche ich in meinem Blog ausführlicher darüber - https://www.tjvantoll.com/2012/07/19/dom-element-references-as-global-variables/ .

TJ VanToll
quelle
3
Nur ein Hinweis auf die offensichtliche Einschränkung der Prämisse, dass "es nicht verwendet werden sollte". Das heißt, "es sollte nicht verwendet werden, es sei denn, Sie sind zufällig ein Code-Cowboy." Code Cowboys machen es einfach.
Jeremy Foster
5
@jeremyfoster Ich stimme überhaupt nicht zu, es sei denn, "Code Cowboy" bedeutet jemanden, der schlechte entwicklerunfreundliche Implementierungen verwendet und verbreitet.
Patrick Roberts
2
Ein Merkmal eines guten Cowboys ist, dass viele anderer Meinung sind. Aber jetzt bin ich wie der philosophische Cowboy oder so ähnlich.
Jeremy Foster
Es sollten mehr Personen das DOM verwenden document.querySelectorAllund darauf document.querySelectorzugreifen. +1 für den guten Vorschlag, das zu verwenden. Der Zugriff auf Elemente per Selektor ist definitiv ein effizienterer Prozess.
Travis J
20

Sie sollten sich getElementById()in folgenden Fällen an Folgendes halten:

document.getElementById('example').innerHTML

IE mischt gerne Elemente mit name und ID Attribute im globalen Namespace, daher ist es am besten, explizit anzugeben, was Sie erhalten möchten.

Nick Craver
quelle
3

Ja, das tun sie.

Getestet in Chrome 55, Firefox 50, IE 11, IE Edge 14 und Safari 10
mit dem folgenden Beispiel:

<!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
quelle
1
Auch in der Oper. Ich denke jedoch, dass die auf dieser Seite geäußerten Einwände gegen diesen Mechanismus sehr gut aufgenommen werden.
ncmathsadist
1

Die Frage sollte lauten: "Werden HTML-Tags mit bereitgestellten IDs zu global zugänglichen DOM-Elementen?"

Die Antwort ist ja!

So sollte es funktionieren, und deshalb wurden IDs von W3C eingeführt: Die ID eines HTML-Tags in einer analysierten Skriptumgebung wird zum entsprechenden DOM-Element-Handle.

Netscape Mozilla weigerte sich jedoch, sich an W3C anzupassen, und verwendete hartnäckig das veraltete Name-Attribut, um Chaos zu verursachen, und brach daher die Skriptfunktionalität und den Codierungskomfort, der durch die Einführung eindeutiger IDs durch W3C verursacht wurde.

Nach dem Fiasko mit Netscape Navigator 4.7 infiltrierten alle ihre Entwickler das W3C, während ihre Mitarbeiter das Web durch falsche Praktiken und missbräuchliche Beispiele ersetzten. Erzwingen der Verwendung und Wiederverwendung des bereits veralteten Namensattributs [!, Das nicht eindeutig sein sollte] auf Augenhöhe mit ID-Attributen, sodass Skripte, die ID-Handles für den Zugriff auf bestimmte DOM-Elemente verwendeten, einfach kaputt gehen!

Und brechen Sie sie, weil sie auch umfangreiche Codierungslektionen und Beispiele schreiben und veröffentlichen würden [ihr Browser würde es sowieso nicht erkennen], document.all.ElementID.propertyanstatt ElementID.propertyes zumindest ineffizient zu machen und dem Browser mehr Overhead zu geben, falls es nicht einfach kaputt geht HTML-Domäne unter Verwendung des gleichen Tokens für den (jetzt [1996-97] veralteten) Namen und das Standard-ID-Attribut, das denselben Token-Wert liefert.

Es gelang ihnen leicht, die damals überwältigende Armee ignoranter Amateure, die Code schreiben, davon zu überzeugen, dass Namen und IDs praktisch identisch sind, mit der Ausnahme, dass das ID-Attribut kürzer und daher bytesparend und für den Codierer bequemer ist als die alte Name-Eigenschaft. Welches war natürlich eine Lüge. Oder - in ihren abgelösten veröffentlichten HTML-Artikeln überzeugen Sie Artikel davon, dass Sie Ihren Tags sowohl Namen als auch ID geben müssen, damit sie für die Scripting-Engine zugänglich sind.

Mosaic Killers [Codename "Mozilla"] waren so sauer, dass sie dachten "Wenn wir untergehen, sollte auch das Internet".

Die aufstrebenden Microsoft-Unternehmen waren dagegen so naiv, dass sie dachten, sie sollten die veraltete und zum Löschen markierte Name-Eigenschaft beibehalten und so behandeln, als wäre es eine ID, die eine eindeutige Kennung darstellt, damit die Skriptfunktionalität von nicht beeinträchtigt wird alte Seiten, die von Netscape-Auszubildenden codiert wurden. Sie haben sich tödlich geirrt ...

Und die Rückgabe einer Array-Sammlung von ID-widersprüchlichen Elementen war auch keine Lösung für dieses absichtlich von Menschen verursachte Problem. Eigentlich hat es den ganzen Zweck besiegt.

Und dies ist der einzige Grund, warum W3C hässlich wurde und uns Idiokien wie document.getElementByIdund die dazugehörige gottverdammte Rokoko-Syntax dieser Art gab ... (...)

Bekim Bacaj
quelle