Les ID d’éléments nommés peuvent être référencés en tant que JavaScript Globals PlatoBlockchain Data Intelligence. Recherche verticale. Aï.

Les ID d'éléments nommés peuvent être référencés en tant que JavaScript Globals

Saviez-vous que les éléments DOM avec ID sont accessibles en JavaScript en tant que variables globales ? C'est une de ces choses qui existe depuis toujours, mais je creuse vraiment dedans pour la première fois.

Si c'est la première fois que vous en entendez parler, préparez-vous ! Nous pouvons le voir en action simplement en ajoutant un ID à un élément en HTML :

Normalement, nous définirions une nouvelle variable en utilisant querySelector("#cool") or getElementById("cool") pour sélectionner cet élément :

var el = querySelector("#cool");

Mais nous avons en fait déjà accès à #cool sans cette rigueur :

Donc tout id - ou name attribut, d'ailleurs - dans le HTML est accessible en JavaScript en utilisant window[ELEMENT_ID]. Encore une fois, ce n'est pas exactement "nouveau" mais c'est vraiment rare à voir.

Comme vous pouvez le deviner, accéder à la portée globale avec des références nommées n'est pas la meilleure idée. Certaines personnes en sont venues à appeler cela le « pollueur de portée mondiale ». Nous verrons pourquoi, mais d'abord…

Un peu de contexte

Cette approche est décrit dans la spécification HTML, où il est décrit comme "l'accès nommé sur le Window objet."

Internet Explorer a été le premier à implémenter la fonctionnalité. Tous les autres navigateurs l'ont également ajouté. Gecko était le seul navigateur à l'époque à ne pas le prendre en charge directement en mode standard, optant plutôt pour en faire une fonctionnalité expérimentale. On a hésité à le mettre en œuvre, mais il a avancé au nom de la compatibilité des navigateurs (Gecko a même essayé de convaincre WebKit pour le sortir du mode standard) et l'a finalement fait passer en mode standard dans Firefox 14.

Une chose qui n'est peut-être pas bien connue est que les navigateurs ont dû mettre en place quelques mesures de précaution - avec plus ou moins de succès - pour s'assurer que les globals générés ne cassent pas la page Web. Une de ces mesures est…

Ombrage variable

La partie la plus intéressante de cette fonctionnalité est probablement que les références d'éléments nommés ne masquer les variables globales existantes. Donc, si un élément DOM a un id qui est déjà défini comme global, il ne remplacera pas celui existant. Par exemple:


  
    window.foo = "bar";
  


  
I won't override window.foo
console.log(window.foo); // Prints "bar"

Et l'inverse est également vrai :

I will be overridden :(
window.foo = "bar"; console.log(window.foo); // Prints "bar"

Ce comportement est essentiel car il annule les dérogations dangereuses telles que

, ce qui créerait sinon un conflit en invalidant le alert API. Cette technique de sauvegarde peut très bien être la raison pour laquelle vous - si vous êtes comme moi - en apprenez pour la première fois.

L'affaire contre les globals nommés

Plus tôt, j'ai dit que l'utilisation d'éléments nommés globaux comme références n'était peut-être pas la meilleure idée. Il y a de nombreuses raisons à cela, qui TJ VanToll a bien couvert sur son blog et je résume ici :

  • Si le DOM change, la référence change également. Cela en fait des produits vraiment « cassants » (le terme de la spécification pour cela) code où la séparation des préoccupations entre HTML et JavaScript pourrait être trop importante.
  • Les références accidentelles sont beaucoup trop faciles. Une simple faute de frappe peut très bien finir par référencer un global nommé et vous donner des résultats inattendus.
  • Il est implémenté différemment dans les navigateurs. Par exemple, nous devrions pouvoir accéder à une ancre avec un id - par exemple — mais certains navigateurs (à savoir Safari et Firefox) renvoient un ReferenceError dans la console.
  • Cela pourrait ne pas renvoyer ce que vous pensez. Selon la spécification, lorsqu'il existe plusieurs instances du même élément nommé dans le DOM - disons, deux instances de

    — le navigateur doit retourner un HTMLCollection avec un tableau des instances. Cependant, Firefox ne renvoie que la première instance. Là encore, la spécification dit nous devons utiliser une instance d'un id dans l'arborescence d'un élément de toute façon. Mais cela n'empêchera pas une page de fonctionner ou quelque chose comme ça.

  • Peut-être y a-t-il un coût de performance ? Je veux dire, le navigateur doit faire cette liste de références et la maintenir. Quelques personnes ont fait des tests dans ce fil StackOverflow, où les variables globales nommées étaient en fait plus performant en un seul test ainsi que moins performant dans un test plus récent.

Considérations supplémentaires

Disons que nous rejetons les critiques contre l'utilisation de globals nommés et que nous les utilisons quand même. C'est parfait. Mais il y a certaines choses que vous voudrez peut-être considérer comme vous le faites.

Polyremplissages

Aussi marginal que cela puisse paraître, ces types de vérifications globales sont une exigence de configuration typique pour les polyfills. Consultez l'exemple suivant où nous définissons un cookie en utilisant le nouveau CookieStore API, en le polyfillant sur les navigateurs qui ne le prennent pas encore en charge :


  
  
    // Polyfill the CookieStore API if not yet implemented.
    // https://developer.mozilla.org/en-US/docs/Web/API/CookieStore
    if (!window.cookieStore) {
      window.cookieStore = myCookieStorePolyfill;
    }
    cookieStore.set("foo", "bar");
  

Ce code fonctionne parfaitement dans Chrome, mais renvoie l'erreur suivante dans Safari :

TypeError: cookieStore.set is not a function

Safari ne prend pas en charge le CookieStore API au moment de la rédaction de cet article. Par conséquent, le polyfill n'est pas appliqué car le img ID d'élément crée une variable globale qui entre en conflit avec le cookieStore globale

Mises à jour de l'API JavaScript

Nous pouvons inverser la situation et trouver un autre problème où les mises à jour du moteur JavaScript du navigateur peuvent casser les références globales d'un élément nommé.

Par exemple :


  
  
    window.BarcodeDetector.focus();
  

Ce script saisit une référence à l'élément d'entrée et appelle focus() dessus. Cela fonctionne correctement. Pourtant, nous ne savons pas comment Long il continuera à fonctionner.

Vous voyez, la variable globale que nous utilisons pour référencer l'élément d'entrée cessera de fonctionner dès que les navigateurs commenceront à prendre en charge le BarcodeDetector API. À ce moment-là, le window.BarcodeDetector global ne sera plus une référence à l'élément d'entrée et .focus() lancera un "window.BarcodeDetector.focus n'est pas une erreur de fonction.

Bonus : tous les éléments nommés ne génèrent pas de références globales

Vous voulez entendre quelque chose de drôle? Pour ajouter l'insulte à la blessure, les éléments nommés ne sont accessibles en tant que variables globales que si les noms ne contiennent que des lettres. Les navigateurs ne créeront pas de référence globale pour un élément dont l'ID contient des caractères spéciaux et des chiffres, comme hello-world ainsi que item1.

Conclusion

Résumons comment nous en sommes arrivés là :

  • Tous les principaux navigateurs créent automatiquement des références globales à chaque élément DOM avec un id (ou, dans certains cas, un name attribut).
  • L'accès à ces éléments via leurs références globales est peu fiable et potentiellement dangereux. Utiliser querySelector or getElementById à la place.
  • Étant donné que les références globales sont générées automatiquement, elles peuvent avoir des effets secondaires sur votre code. C'est une bonne raison d'éviter d'utiliser le id attribut sauf si vous en avez vraiment besoin.

En fin de compte, c'est probablement une bonne idée d'éviter d'utiliser des globals nommés en JavaScript. J'ai cité la spécification plus tôt sur la façon dont cela conduit à un code "fragile", mais voici le texte complet pour enfoncer le clou :

En règle générale, s'appuyer sur cela conduira à un code fragile. Les identifiants qui finissent par être mappés à cette API peuvent varier au fil du temps, à mesure que de nouvelles fonctionnalités sont ajoutées à la plate-forme Web, par exemple. Au lieu de cela, utilisez document.getElementById() or document.querySelector().

Je pense que le fait que la spécification HTML elle-même recommande de rester à l'écart de cette fonctionnalité parle de lui-même.

Horodatage:

Plus de Astuces CSS