Os elementos da árvore DOM com IDs se tornam variáveis ​​globais?

364

Trabalhando em uma idéia para um invólucro HTMLElement simples, deparei-me com o seguinte para Internet Explorer e Chrome :

Para um determinado HTMLElement com ID na árvore DOM, é possível recuperar a div usando seu ID como o nome da variável. Então, para uma div como

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

no Internet Explorer 8 e Chrome, você pode:

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

ou

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

Então, isso significa que todos os elementos na árvore DOM são convertidos em uma variável no espaço para nome global? E isso também significa que se pode usar isso como um substituto para o getElementByIdmétodo nesses navegadores?

KooiInc
fonte
11
@ Bergi, o comentário que afirma não fazer isso agora está desatualizado e até inválido. Portanto, não consigo encontrar um motivo concreto para não usar esse recurso.
ESR
@ EdmundReed Você pode querer ler a resposta da pergunta vinculada novamente - ainda é uma péssima idéia: " variáveis ​​globais declaradas implicitamente " não têm suporte a ferramentas ou levam a um código quebradiço . Não chame isso de "recurso", a resposta abaixo explica como é apenas um bug que se tornou parte do padrão por razões de compatibilidade.
Bergi
11
@ Bergi justo o suficiente, você está certo. Ainda acho que é um recurso realmente interessante, e só é considerado problemático porque as pessoas não estão cientes disso. É assim que eu imagino usá-lo: codepen.io/esr360/pen/WEavGE?editors=1000#0
ESR
@EdmundReed É menos problemático se você não separar adequadamente o conteúdo e a lógica, é claro. Também recomendo nunca usar manipuladores de eventos em linha ou instalar métodos personalizados em elementos DOM que os abusem como espaços de nome (observe que não é um "escopo").
Bergi 29/08/19

Respostas:

395

O que deveria acontecer é que 'elementos nomeados' são adicionados como propriedades aparentes do documentobjeto. Essa é uma péssima idéia, pois permite que os nomes dos elementos colidam com as propriedades reais de document.

O IE piorou a situação adicionando também elementos nomeados como propriedades do windowobjeto. Isso é duplamente ruim, pois agora você deve evitar nomear seus elementos depois que qualquer membro do documentou do windowobjeto que você (ou qualquer outro código de biblioteca do seu projeto) desejar usar.

Isso também significa que esses elementos são visíveis como variáveis ​​globais. Felizmente, neste caso, qualquer declaração varou global real functionno seu código as sombreia, então você não precisa se preocupar muito com a nomeação aqui, mas se você tentar fazer uma atribuição a uma variável global com um nome conflitante e se esquecer de declarar -lo var, você vai ter um erro no IE, enquanto ele tenta atribuir o valor para o próprio elemento.

Geralmente, é considerado uma má prática omitir var, além de contar com elementos nomeados visíveis windowou globais. Atenha-se a document.getElementById, que é mais suportado e menos ambíguo. Você pode escrever uma função de invólucro trivial com um nome mais curto se não gostar da digitação. De qualquer maneira, não faz sentido usar um cache de pesquisa de identificação para elemento, porque os navegadores geralmente otimizam a getElementByIdchamada para usar uma pesquisa rápida de qualquer maneira; tudo o que você obtém são problemas quando elementos idsão alterados ou adicionados / removidos do documento.

O Opera copiou o IE, depois o WebKit se juntou, e agora a prática anteriormente não padronizada de colocar elementos nomeados nas documentpropriedades, e a prática anterior apenas no IE de colocá-loswindow estão sendo padronizadas pelo HTML5, cuja abordagem é documentar e padronizar todos os prática terrível infligida a nós pelos autores dos navegadores, tornando-os parte da Web para sempre. Portanto, o Firefox 4 também suporta isso.

O que são 'elementos nomeados'? Qualquer coisa com um id, e qualquer coisa com um namesendo usado para fins de 'identificação': ou seja, formulários, imagens, âncoras e algumas outras, mas não outras instâncias não relacionadas de um nameatributo, como nomes de controle nos campos de entrada de formulário, nomes de parâmetro em <param>ou digite os metadados <meta>. 'Identificar' nameé o que deve ser evitado em favor de id.

bobince
fonte
5
Essa é uma resposta clara, obrigado. Não foi minha idéia omitir document.getElementById (bem, na verdade, eu uso o xpath sempre que possível para procurar propriedades de elementos / elementos hoje em dia). Eu me deparei com essa prática (ruim) de itens nomeados e fiquei curiosa para saber de onde vinha. Você respondeu isso o suficiente; agora sabemos por que ele também pode ser encontrado no Chrome (webkit).
KooiInc 08/08
18
Uma exceção ao "uso de namedeve ser evitada" é com <input>, onde o nameatributo desempenha um papel crítico na formação da chave dos pares de valor-chave para envio de formulários.
Yahel
7
Para sua informação, o Firefox só faz isso quando colocado no modo peculiar.
Crescent Fresh
4
@ yahelc: é exatamente essa a distinção que estou fazendo. “Não outros usos namecomo o controle de nomes em campos de entrada forma ...”
bobince
13
PORQUE!? Existe algo que possamos fazer para acabar com essa loucura? Minhas funções foram redefinidas por referências a elementos e levou uma hora para eu depurar. :(
Farzher
52

Conforme mencionado na resposta anterior, esse comportamento é conhecido como acesso nomeado no objeto de janela . O valor do nameatributo para alguns elementos e o valor do idatributo para todos os elementos são disponibilizados como propriedades do windowobjeto global . Estes são conhecidos como elementos nomeados. Como windowé o objeto global no navegador, cada elemento nomeado estará acessível como uma variável global.

Isso foi originalmente adicionado pelo Internet Explorer e, eventualmente, foi implementado por todos os outros navegadores simplesmente para compatibilidade com sites que dependem desse comportamento. Curiosamente, o Gecko (mecanismo de renderização do Firefox) optou por implementá-lo apenas no modo quirks , enquanto outros mecanismos de renderização o deixaram no modo padrão.

No entanto, a partir do Firefox 14, o Firefox agora também oferece suporte ao acesso nomeado ao windowobjeto no modo de padrões. Por que eles mudaram isso? Acontece que ainda existem muitos sites que dependem dessa funcionalidade no modo de padrões. A Microsoft até lançou uma demonstração de marketing , impedindo que ela funcionasse no Firefox.

O Webkit considerou recentemente o oposto , relegando o acesso nomeado nowindow objeto apenas ao modo quirks. Eles decidiram contra o mesmo raciocínio que Gecko.

Tão ... louco que pareça que esse comportamento agora seja tecnicamente seguro para uso na versão mais recente de todos os principais navegadores no modo de padrões . Porém, embora o acesso nomeado possa parecer um tanto conveniente, ele não deve ser usado .

Por quê? Muito do raciocínio pode ser resumido neste artigo sobre por que as variáveis ​​globais são ruins . Simplificando, ter um monte de variáveis ​​globais extras leva a mais erros. Digamos que você acidentalmente digite o nome de a vare digite umaid de um nó DOM, SURPRISE!

Além disso, apesar de padronizados, ainda existem algumas discrepâncias nas implementações do navegador de acesso nomeado.

  • IE incorretamente torna o valor do name atributo acessível para elementos de formulário (entrada, seleção, etc.).
  • O Gecko e o Webkit incorretamente NÃO tornam as <a>tags acessíveis por meio de seusname atributos.
  • O Gecko manipula incorretamente vários elementos nomeados com o mesmo nome (retorna uma referência a um único nó em vez de uma matriz de referências).

E tenho certeza de que há mais se você tentar usar o acesso nomeado em casos extremos.

Conforme mencionado em outras respostas, use document.getElementByIdpara obter uma referência a um nó DOM por ele id. Se você precisar obter uma referência a um nó por seu nameatributo use document.querySelectorAll.

Por favor, não propague esse problema usando o acesso nomeado em seu site. Muitos desenvolvedores da Web perderam tempo tentando rastrear esse comportamento mágico . Nós realmente precisamos agir e fazer com que os mecanismos de renderização desativem o acesso nomeado no modo de padrões. No curto prazo, ele interromperá alguns sites que fazem coisas ruins, mas, a longo prazo, ajudará a avançar a web.

Se você estiver interessado, eu falo sobre isso com mais detalhes no meu blog - https://www.tjvantoll.com/2012/07/19/dom-element-references-as-global-variables/ .

TJ VanToll
fonte
3
Apenas uma nota à ressalva óbvia da premissa de que "não deve ser usada". Ou seja, "não deve ser usado, a menos que você seja um cowboy de código". Os cowboys de código simplesmente fazem isso.
Jeremy Foster
5
@jeremyfoster, a menos que "cowboy de código" signifique alguém que use e propague implementações ruins e pouco amigáveis ​​aos desenvolvedores, discordo totalmente.
Patrick Roberts
2
Uma marca de um bom cowboy é que muitos discordam. Mas agora eu sou como o cowboy filosófico ou algo assim.
Jeremy Foster
Mais pessoas devem estar usando document.querySelectorAlle document.querySelectorao acessar o DOM. +1 pela boa sugestão de usar isso. Acessar elementos pelo seletor é definitivamente um processo mais eficiente.
Travis J
20

Você deve getElementById()seguir esses casos, por exemplo:

document.getElementById('example').innerHTML

O IE gosta de misturar elementos name e ID atributos no espaço para nome global, para melhor ser explícito sobre o que você está tentando obter.

Nick Craver
fonte
3

Sim, eles fazem.

Testado no Chrome 55, Firefox 50, IE 11, IE Edge 14 e Safari 10
com o seguinte exemplo:

<!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
fonte
11
Também no Opera. No entanto, acho que a objeção a esse mecanismo expressa nesta página é muito bem aceita.
Ncmathsadist
1

A pergunta deve soar: "As tags HTML com os IDs fornecidos tornam-se elementos DOM acessíveis globalmente?"

A resposta é sim!

Foi assim que funcionou e é por isso que os IDs foram introduzidos pelo W3C para começar: O ID de uma tag HTML em um ambiente de script analisado se torna seu identificador de elemento DOM correspondente.

No entanto, o Netscape Mozilla se recusou a obedecer (para eles se intrometerem) no W3C e continuou teimosamente usando o atributo Name obsoleto para criar estragos e, portanto, interromper a funcionalidade de script e a conveniência de codificação trazidas pela introdução de IDs exclusivas do W3C.

Após o fiasco do Netscape Navigator 4.7, todos os desenvolvedores foram e se infiltraram no W3C, enquanto seus associados estavam substituindo a Web com práticas erradas e exemplos de uso indevido. Forçando o uso e reutilização do atributo Name já reprovado [! Que não era para ser exclusivo], a par dos atributos de ID, para que os scripts que utilizavam identificadores de ID para acessar determinados elementos DOM simplesmente quebrassem!

E quebrar eles fizeram como eles também iria escrever e publicar aulas de codificação extensos e exemplos [seu navegador não reconheceria qualquer maneira] como document.all.ElementID.propertyem vez de ElementID.property, pelo menos, torná-lo ineficaz e dar o navegador mais sobrecarga no caso de ele não simplesmente quebrá-lo em Domínio HTML usando o mesmo token para o Nome (agora [1996-97], descontinuado) e o atributo de ID padrão que fornece o mesmo valor de token.

Eles conseguiram facilmente convencer o exército esmagador de amadores ignorantes de escrita de código de que Nomes e IDs são praticamente os mesmos, exceto que o atributo ID é mais curto e, portanto, economiza bytes e é mais conveniente para o codificador do que a antiga propriedade Name. O que era obviamente uma mentira. Ou - nos artigos publicados em HTML substituídos, convencer os artigos de que você precisará fornecer Nome e ID às suas tags para que elas sejam acessíveis pelo mecanismo de Script.

Os Mosaic Killers [codinome "Mozilla"] ficaram tão irritados que pensaram "se descermos, a Internet também deveria".

A crescente Microsoft - por outro lado - era tão ingênua que achava que deveria manter a propriedade Reprovada e marcada para exclusão Name e tratá-la como se fosse um ID que seja um Identificador exclusivo, para que não quebrassem a funcionalidade de script do páginas antigas codificadas por trainees da Netscape. Eles estavam mortalmente errados ...

E o retorno de uma coleção de elementos conflitantes de ID também não era uma solução para esse problema deliberado causado pelo homem. Na verdade, derrotou todo o propósito.

E essa é a única razão pela qual o W3C ficou feio e nos deu idiotices como document.getElementByIda sintaxe rococó e irritante que o acompanha ... (...)

Bekim Bacaj
fonte