¿Los elementos del árbol DOM con identificadores se convierten en variables globales?

364

Trabajando en una idea para un simple contenedor HTMLElement, me topé con lo siguiente para Internet Explorer y Chrome :

Para un elemento HTMLE dado con ID en el árbol DOM, es posible recuperar el div usando su ID como nombre de variable. Entonces para un div como

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

en Internet Explorer 8 y Chrome puedes hacer:

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

o

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

Entonces, ¿esto significa que cada elemento en el árbol DOM se convierte en una variable en el espacio de nombres global? ¿Y también significa que uno puede usar esto como un reemplazo para el getElementByIdmétodo en estos navegadores?

KooiInc
fuente
1
@Bergi, el comentario que dice no hacer esto ahora está desactualizado e incluso no es válido. Por lo tanto, no puedo encontrar una razón concreta para no usar esta función.
ESR
@EdmundReed Es posible que desee volver a leer la respuesta de la pregunta vinculada: sigue siendo una mala idea: las " variables globales declaradas implícitamente " no tienen soporte de herramientas y " conducen a un código quebradizo ". No lo llame una "característica", la respuesta a continuación explica cómo es solo un error que se convirtió en parte del estándar por razones de compatibilidad.
Bergi
1
@Bergi es justo, tienes razón. Sin embargo, sigo pensando que es una característica muy interesante, y solo se considera problemática porque las personas no son conscientes de ello. Así es como imagino usarlo: codepen.io/esr360/pen/WEavGE?editors=1000#0
ESR
@EdmundReed Es menos problemático si no separas correctamente el contenido y la lógica, por supuesto. También recomiendo nunca usar controladores de eventos en línea o instalar métodos personalizados en elementos DOM abusándolos como espacios de nombres (tenga en cuenta que no es un "alcance").
Bergi

Respuestas:

395

Lo que se supone que sucede es que los "elementos con nombre" se agregan como propiedades aparentes de document objeto. Esta es una muy mala idea, ya que permite que los nombres de elementos entren en conflicto con propiedades reales de document.

IE empeoró la situación al agregar también elementos nombrados como propiedades de window objeto. Esto es doblemente malo, ya que ahora debe evitar nombrar sus elementos después de que cualquier miembro del objeto documento del windowobjeto (o cualquier otro código de biblioteca en su proyecto) quiera usar.

También significa que estos elementos son visibles como variables de tipo global. Afortunadamente en este caso cualquier real global varofunction declaración en su código los sombrea, por lo que no debe preocuparse tanto por nombrar aquí, pero si intenta asignar una variable global con un nombre en conflicto y olvida declarar que var, obtendrá un error en el IE, ya que trata de asignar el valor al elemento en sí.

En general, se considera una mala práctica omitir var, así como confiar en que los elementos con nombre sean visibles windowo globales. Apéguese a document.getElementById, que es más ampliamente compatible y menos ambiguo. Puede escribir una función de envoltura trivial con un nombre más corto si no le gusta escribir. De cualquier manera, no tiene sentido usar un caché de búsqueda de id a elemento, porque los navegadores generalmente optimizan la getElementByIdllamada para usar una búsqueda rápida de todos modos; todo lo que obtienes son problemas cuando los elementos cambian ido se agregan / eliminan del documento.

Opera copió IE, luego WebKit se unió, y ahora tanto la práctica no estandarizada anteriormente de poner elementos con nombre en las documentpropiedades, como la práctica anterior de IE solo de ponerlos windowestán siendo estandarizados por HTML5, cuyo enfoque es documentar y estandarizar cada terrible práctica que nos infligieron los autores de los navegadores, haciéndolos parte de la web para siempre. Entonces Firefox 4 también será compatible con esto.

¿Qué son los 'elementos nombrados'? Cualquier cosa con un objeto idy cualquier cosa con un nameser utilizado para propósitos de 'identificación': es decir, formularios, imágenes, anclas y algunos otros, pero no otras instancias no relacionadas de un nameatributo, como nombres de control en campos de entrada de formulario, nombres de parámetros en <param>o escriba metadatos <meta>. Las "identificaciones" nameson las que deberían evitarse a favor id.

bobince
fuente
55
Esa es una respuesta clara, gracias. No fue mi idea omitir document.getElementById (bueno, de hecho, uso xpath siempre que sea posible para buscar elementos / propiedades de elementos hoy en día). Me topé con esta (mala) práctica para artículos con nombre y tenía curiosidad sobre de dónde venía. Respondiste eso lo suficiente; ahora sabemos por qué también se puede encontrar en Chrome (webkit).
KooiInc
18
Una excepción a " namedebe evitarse el uso de " es con <input>, donde el nameatributo juega un papel crítico en la formación de la clave de los pares clave-valor para los envíos de formularios.
Yahel
77
FYI Firefox solo hace esto cuando se pone en modo peculiaridades.
Crescent Fresh
44
@yahelc: esa es exactamente la distinción que estoy haciendo. "No otros usos de namenombres de control similares en campos de entrada de formulario ..."
bobince
13
¿¡POR QUÉ!? ¿Hay algo que podamos hacer para detener esta locura? Mis funciones se redefinieron por referencias a elementos y me llevó una hora depurar. :(
Farzher
52

Como se mencionó en la respuesta anterior, este comportamiento se conoce como acceso con nombre en el objeto de la ventana . El valor del nameatributo para algunos elementos y el valor del idatributo para todos los elementos están disponibles como propiedades del windowobjeto global . Estos se conocen como elementos nombrados. Ya quewindow es el objeto global en el navegador, cada elemento nombrado será accesible como una variable global.

Esto fue agregado originalmente por Internet Explorer y eventualmente fue implementado por todos los otros navegadores simplemente por compatibilidad con sitios que dependen de este comportamiento. Curiosamente, Gecko (el motor de renderizado de Firefox) eligió implementar esto en modo peculiar. , mientras que otros motores de renderizado lo dejaron en modo estándar.

Sin embargo, a partir de Firefox 14, Firefox ahora también admite el acceso con nombre en el windowobjeto en modo estándar. ¿Por qué cambiaron esto? Resulta que todavía hay muchos sitios que dependen de esta funcionalidad en modo estándar. Microsoft incluso lanzó una demostración de marketing que lo hizo, evitando que la demostración funcione en Firefox.

Webkit ha considerado recientemente lo contrario , relegando el acceso con nombre en el windowobjeto al modo peculiar solamente. Decidieron no hacerlo por el mismo razonamiento que Gecko.

Entonces ... por extraño que parezca, este comportamiento ahora es técnicamente seguro de usar en la última versión de todos los principales navegadores en modo estándar . Pero aunque el acceso con nombre puede parecer algo conveniente, no debe usarse .

¿Por qué? Gran parte del razonamiento se puede resumir en este artículo sobre por qué las variables globales son malas . En pocas palabras, tener un montón de variables globales adicionales conduce a más errores. Digamos que accidentalmente escribe el nombre de a vary sucede que escribe un idnodo DOM, ¡SORPRESA!

Además, a pesar de estar estandarizado, todavía hay algunas discrepancias en las implementaciones de acceso con nombre del navegador.

  • IE hace incorrectamente nameaccesible el valor del atributo para los elementos del formulario (entrada, selección, etc.).
  • Gecko y Webkit incorrectamente NO hacen que las <a>etiquetas sean accesibles a través de sus nameatributos.
  • Gecko maneja incorrectamente varios elementos con el mismo nombre (devuelve una referencia a un solo nodo en lugar de una matriz de referencias).

Y estoy seguro de que hay más si intenta usar el acceso con nombre en casos extremos.

Como se menciona en otras respuestas, use document.getElementByIdpara obtener una referencia a un nodo DOM por su id. Si necesita obtener una referencia a un nodo por su nameuso de atributo document.querySelectorAll.

Por favor, no propague este problema utilizando acceso con nombre en su sitio. Muchos desarrolladores web han perdido el tiempo tratando de rastrear este comportamiento mágico . Realmente necesitamos tomar medidas y obtener motores de renderizado para desactivar el acceso con nombre en modo estándar. A corto plazo, romperá algunos sitios que hacen cosas malas, pero a la larga ayudará a que la web avance.

Si está interesado, hablo sobre esto con más detalle en mi blog: https://www.tjvantoll.com/2012/07/19/dom-element-references-as-global-variables/ .

TJ VanToll
fuente
3
Solo una nota a la obvia advertencia de la premisa de que "no debe usarse". Es decir, "no debe usarse A MENOS QUE sea un código cowboy". Los vaqueros de código solo lo intentan.
Jeremy Foster, el
55
@jeremyfoster a menos que "código cowboy" se refiera a alguien que usa y propaga implementaciones malas para desarrolladores poco amigables, estoy totalmente en desacuerdo.
Patrick Roberts
2
Una marca de un buen vaquero es que muchos no están de acuerdo. Pero ahora soy como el vaquero filosófico o algo así.
Jeremy Foster
Más personas deberían estar usando document.querySelectorAlly document.querySelectoral acceder al DOM. +1 por la buena sugerencia de usar eso. Acceder a los elementos por selector es definitivamente un proceso más eficiente.
Travis J
20

Debe atenerse getElementById()en estos casos, por ejemplo:

document.getElementById('example').innerHTML

A IE le gusta mezclar elementos name y ID atributos en el espacio de nombres global, por lo que es mejor ser explícito sobre lo que está tratando de obtener.

Nick Craver
fuente
3

Ellos si.

Probado en Chrome 55, Firefox 50, IE 11, IE Edge 14 y Safari 10
con el siguiente ejemplo:

<!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
fuente
1
También en ópera. Sin embargo, creo que la objeción a este mecanismo expresada en esta página está muy bien tomada.
ncmathsadist
1

La pregunta debería sonar: "¿Las etiquetas HTML con las ID proporcionadas se convierten en elementos DOM accesibles globalmente?"

¡La respuesta es sí!

Así es como debía funcionar, y es por eso que W3C introdujo las ID para empezar: la ID de una etiqueta HTML en un entorno de secuencias de comandos analizadas se convierte en su correspondiente identificador de elemento DOM.

Sin embargo, Netscape Mozilla se negó a ajustarse al W3C (intruso) y obstinadamente siguió usando el atributo de Nombre en desuso para crear estragos y, por lo tanto, romper la funcionalidad de Scripting y la conveniencia de codificación introducida por la introducción de ID únicos del W3C.

Después del fiasco de Netscape Navigator 4.7, todos sus desarrolladores se infiltraron en el W3C, mientras que sus asociados estaban reemplazando a la Web con prácticas incorrectas y ejemplos de mal uso. Forzando el uso y la reutilización del atributo de Nombre ya en desuso [! Que no estaba destinado a ser único] a la par con los atributos de ID para que los scripts que utilizaban identificadores de ID para acceder a elementos DOM particulares simplemente se rompieran!

Y rompieron, ya que también escribirían y publicarían extensas lecciones y ejemplos de codificación [su navegador no reconocería de todos modos], como en document.all.ElementID.propertylugar de ElementID.propertyal menos hacerlo ineficiente y darle al navegador más sobrecarga en caso de que simplemente no lo rompiera Dominio HTML utilizando el mismo token para el Nombre (ahora [1996-97], en desuso) y el atributo ID estándar que le proporciona el mismo valor de token.

Fácilmente lograron convencer al ejército abrumador de aficionados ignorantes de la escritura de códigos de que los nombres y las identificaciones son prácticamente iguales, excepto que el atributo de identificación es más corto y, por lo tanto, ahorra bytes y es más conveniente para el codificador que la antigua propiedad de nombre. Lo cual, por supuesto, era una mentira. O bien, en su reemplazo de artículos publicados de HTML, artículos convincentes de que deberá proporcionar tanto el nombre como la identificación a sus etiquetas para que el motor de secuencias de comandos pueda acceder a ellos.

Los Asesinos de mosaicos [con nombre en código "Mozilla"] estaban tan enojados que pensaron "si caemos, también debería hacerlo Internet".

El Microsoft en ascenso, por otro lado, era tan ingenuo que pensó que debería mantener la propiedad Name en desuso y marcada para su eliminación y tratarla como si fuera una ID que es un identificador único para que no rompieran la funcionalidad de scripting de páginas antiguas codificadas por aprendices de Netscape. Estaban mortalmente equivocados ...

Y la devolución de una colección de elementos conflictivos de ID tampoco fue una solución a este problema deliberado hecho por el hombre. En realidad, derrotó todo el propósito.

Y esta es la única razón por la que W3C se volvió feo y nos dio idioteces como document.getElementByIdy la sintaxis molesta rococó que la acompaña ... (...)

Bekim Bacaj
fuente