web-dev-qa-db-fra.com

Pourquoi n'utilisons-nous pas simplement les identifiants d'éléments comme identifiants dans JavaScript?

Tous les navigateurs avec lesquels je suis venu travailler permettent d'accéder à un élément avec id="myDiv" en écrivant simplement:

myDiv

Voir ici: http://jsfiddle.net/L91q54Lt/

Quoi qu’il en soit, cette méthode semble assez mal documentée et, en fait, les sources que j’ai rencontrées ne la mentionnent même pas et supposent au contraire qu’on utiliserait

document.getElementById("myDiv")

ou peut-être

document.querySelector("#myDiv")

d'accéder à un élément DOM même lorsque son identifiant est connu à l'avance (c'est-à-dire non calculé au moment de l'exécution). Je peux dire que ces dernières approches ont l’avantage de protéger le code si quelqu'un essaye par inadvertance de redéfinir myDiv dans un contexte plus large (ce n’est pas une idée aussi brillante ...), l’écrase avec une valeur différente et continue sans remarquer le choc.

Mais autre que ça? Y a-t-il des problèmes d'utilisation du formulaire abrégé ci-dessus autres que la conception de code, ou quoi d'autre me manque ici?

48
GOTO 0

Quoi qu'il en soit, cette méthode semble assez mal documentée et, en fait, les sources que je rencontre ne la mentionnent même pas [...]

Mis à part les variables globales implicitement déclarées, le manque de documentation est une excellente raison de ne pas l'utiliser. 

La promotion apparente des valeurs id en variables globales n’est pas conforme aux normes (le spécification HTML5 pour l’attribut ID ne le mentionne pas) et vous ne devez donc pas présumer que les futurs navigateurs le mettront en œuvre.

EDIT: Il se trouve que ce comportement est conforme aux normes - En HTML5, window devrait prendre en charge l’accès aux propriétés des "éléments nommés":

Les objets nommés avec le nom nommé, aux fins de l'algorithme ci-dessus, sont ceux qui sont:

  • les contextes de navigation enfants du document actif dont le nom est nom
  • a, applet, area, embed, form, frameset, img ou object elements qui ont un attribut de contenu de nom dont la valeur est nom, ou 
  • Éléments HTML ayant un attribut de contenu id dont la valeur est nom.

Source: Spéc. HTML 5, 'Accès nommé à un objet window " , emphase mine.

Sur cette base, le respect des normes n’est pas une raison pour éviter ce phénomène. Cependant, la spéc elle-même déconseille son utilisation:

En règle générale, le fait de s’en remettre à cela conduira à un code fragile. Lequel En fin de compte, les identificateurs mappés sur cette API peuvent varier dans le temps, en fonction des nouvelles fonctionnalités ajouté à la plate-forme Web, par exemple. Au lieu de cela, utilisez document.getElementById() ou document.querySelector().

41
joews

Excellente question. Comme Einstein ne l’a probablement pas dit, les choses devraient être aussi simples que possible, et non plus simples.

ces dernières approches ont l'avantage de garder le code en sécurité si quelqu'un tente par inadvertance de redéfinir myDiv dans un contexte plus large (pas une idée aussi brillante cependant ...), l'écrase avec une valeur différente et continue sans remarquer le choc

C’est la raison principale pour laquelle c’est une mauvaise idée, et c’est assez. Les variables globales ne sont pas sûres. Ils peuvent être écrasés à tout moment, par tout script éventuellement exécuté sur la page.

De plus, il suffit de taper myDiv pour créer une «forme abrégée» de document.getElementById(). C'est une référence à une variable globale .document.getElementById() retournera volontiers null si l'élément n'existe pas, alors que tenter d'accéder à une variable globale inexistante génèrera une erreur de référence, vous aurez donc besoin d'envelopper vos références au global un bloc try/catch pour être en sécurité.

C'est l'une des raisons pour lesquelles jQuery est si populaire: si vous faites $("#myDiv").remove(), et qu'il n'y a pas d'élément avec un identifiant de myDiv, aucune erreur ne sera renvoyée - le code ne fera que rien silencieusement, ce qui est souvent exactement ce que vous voulez en faisant DOM manipulation.

19
Paul D. Waite

Il y a quelques raisons:

Vous ne voulez pas que votre code et votre balise soient couplés.

En utilisant un appel spécifique pour accéder à une div, vous n'avez pas à vous soucier de la corruption de l'espace global. Ajoutez une bibliothèque qui déclare myDiv dans l’espace global et vous vous retrouvez dans un monde de douleur qui sera difficile à résoudre.

Vous pouvez accéder aux éléments, par ID, qui ne font pas partie du DOM

Ils peuvent être dans un fragment, un cadre ou un élément qui a été détaché et pas encore rattaché au DOM.

EDIT: Exemple d'accès à des éléments non attachés par ID

var frag = document.createDocumentFragment();
var span = document.createElement("span");
span.id = "span-test";
frag.appendChild(span);
var span2 = frag.getElementById("span-test");
alert(span === span2);

12
Jeremy J Starcher

Dans mon cas, j'avais un iframe dans ma page. J'ai été dérouté par l'attribut id contre l'attribut name, qui ont tous deux affecté une variable nommée inner_iframe, accessible à partir de window!

  • Si je n'utilisais que l'attribut id, comme id="inner_iframe", je pourrais accéder aux propriétés contentDocument et contentWindowcomme décrit ici * Dans ce cas id, inner_iframe représente un HTMLIFrameElement.

  • Si je n'utilisais que l'attribut name, comme name="inner_iframe", je ne pourrais pas accéder aux propriétés ci-dessus contentDocument ou contentWindow; dans ce cas name, inner_iframe représente un "cadre", autrement dit un "objet window" ; c’est-à-dire le résultat de l’appel contentWindow **

  • Si j’utilisais les attributs bothname et id, et que je donnais aux deux attributs la même valeur name="inner_iframe" id="inner-iframe"; l'attribut name a dépassé/a détruit l'attribut id; Il me restait l'objet "window", pas le HTMLIFrameElement!

Donc, mon point est de faire attention à l'ambiguïté; le conflit entre les attributs name et id sur le même objet avec deux API différentes: il s'agit simplement d'un cas spécifique dans lequel le comportement implicite et l'attachement à une variable window peut vous semer la confusion.

* (et uniquement si le <script> a été chargé après/sous le <iframe> dans le code HTML ou si le <script> a attendu le window.onload avant d'essayer d'accéder à l'attribut id)

** Cette distinction "cadre"/élément DOM est décrite dans la documentation de Mozilla comme suit:

Chaque élément du pseudo-tableau window.frames représente l’objet window correspondant au contenu donné, pas l’élément DOM de la trame (i) (c.-à-d. Window.frames [0] est la même chose comme document.getElementsByTagName ("iframe") [0] .contentWindow).

1
The Red Pea