web-dev-qa-db-fra.com

À quel point est-il dangereux en JavaScript de supposer qu'un non défini n'est pas écrasé?

Chaque fois que quelqu'un mentionne un test contre undefined, il est souligné que undefined n'est pas un mot clé donc il pourrait être défini sur "hello" , donc vous devez utilisertypeof x == "undefined" au lieu. Cela me semble ridicule. Personne ne ferait jamais ça, et s'ils le faisaient, ce serait une raison suffisante pour ne jamais utiliser le code qu'ils ont écrit ... n'est-ce pas?

J'ai trouvé n exemple de quelqu'un qui a accidentellement défini undefined sur null, et cela a été donné comme une raison pour éviter de supposer que undefined n'est pas écrasé. Mais s'ils l'avaient fait, le bogue n'aurait pas été détecté, et je ne vois pas comment c'est mieux.

En C++, tout le monde sait qu'il est légal de dire #define true false, mais personne ne vous conseille d'éviter de true et d'utiliser 0 == 0 au lieu. Vous supposez simplement que personne ne serait jamais assez gros pour faire ça, et s'ils le font, ne faites plus jamais confiance à leur code.

Cela a-t-il déjà mordu quelqu'un là où quelqu'un d'autre a été affecté à undefined (exprès) et cela a brisé votre code, ou s'agit-il davantage d'une menace hypothétique? Je suis prêt à tenter ma chance pour rendre mon code légèrement plus lisible. Est-ce vraiment une mauvaise idée?

Pour réitérer, je ne demande pas comment se protéger contre une réaffectation non définie. J'ai déjà vu ces astuces écrites 100 fois. Je demande à quel point il est dangereux de ne pas utiliser ces astuces.

85
Cosmologicon

Non, je ne l'ai jamais fait. C'est principalement parce que je développe sur des navigateurs modernes, qui sont pour la plupart conformes à ECMAScript 5. La norme ES5 stipule que undefined est désormais en lecture seule. Si vous utilisez le mode strict (vous devriez), une erreur sera levée si vous essayez accidentellement de le modifier.

undefined = 5;
alert(undefined); // still undefined
'use strict';
undefined = 5; // throws TypeError

Ce que vous devez pas faire est de créer votre propre undefined:

(function (undefined) {
    // don't do this, because now `undefined` can be changed
    undefined = 5;
})();

Constant va bien. Toujours inutile, mais très bien.

(function () {
    const undefined = void 0;
})();
56
Ry-

Aucun code approprié ne fera une telle chose. Mais vous ne pouvez jamais savoir ce qu'a fait un développeur intelligent ou un plugin/bibliothèque/script que vous utilisez. D'un autre côté, il est extrêmement improbable et les navigateurs modernes ne permettront pas du tout d'écraser undefined, donc si vous utilisez un tel navigateur pour le développement, vous remarquerez rapidement si du code essaie de l'écraser.


Et même si vous ne l'avez pas demandé - beaucoup de gens trouveront probablement cette question lors de la recherche du problème le plus courant "comment se protéger contre undefined" redéfini, donc je répondrai quand même:

Il existe un très bon moyen d'obtenir un véritable non définiundefined quel que soit l'âge du navigateur:

(function(undefined) {
    // your code where undefined is undefined
})();

Cela fonctionne car un argument non spécifié est toujours undefined. Vous pouvez également le faire avec une fonction qui accepte certains arguments réels, par exemple comme ceci lorsque vous utilisez jQuery. C'est généralement une bonne idée de garantir un environnement sain de cette manière:

(function($, window, undefined) {
    // your code where undefined is undefined
})(jQuery, this);

Ensuite, vous pouvez être sûr qu'à l'intérieur de cette fonction anonyme, les choses suivantes sont vraies:

  • $ === jQuery
  • window === [the global object]
  • undefined === [undefined].

Cependant, notez que parfois typeof x === 'undefined' Est en fait nécessaire: si la variable x n'a jamais été définie sur une valeur (contrairement à set à undefined ), la lecture de x d'une manière différente telle que if(x === undefined) générera une erreur. Cela ne s'applique cependant pas aux propriétés des objets, donc si vous savez que y est toujours un objet, if(y.x === undefined) est parfaitement sûr.

40
ThiefMaster

Il existe une solution simple: comparer avec void 0 qui est toujours indéfini.

Notez que vous devez éviter == car cela peut contraindre les valeurs. Utilisation === (et !==) au lieu.

Cela dit, la variable non définie peut être définie par erreur si quelqu'un écrit = au lieu de == lors de la comparaison de quelque chose avec undefined.

19
Lucero

Vous seul savez quel code vous utilisez, et donc à quel point il est dangereux. Il est impossible de répondre à cette question de la manière dont vous avez précisé que vous souhaitez y répondre.

1) Créez une stratégie d'équipe, interdisez la redéfinition indéfinie, en la réservant à son utilisation la plus populaire. Scannez votre code existant pour une affectation à gauche non définie.

2) Si vous ne contrôlez pas tous les scénarios, si votre code est utilisé en dehors de situations que vous ou vos politiques contrôlez, alors évidemment votre réponse est différente. Scannez le code qui utilise vos scripts. Heck, scannez le web pour des statistiques d'affectation gauche indéfinie si vous le souhaitez, mais je doute que cela ait été fait pour vous, car il est plus facile de poursuivre la réponse # 1 ou # 3 ici à la place.

3) Et si cette réponse n'est pas assez bonne, c'est probablement parce que, encore une fois, vous avez besoin d'une réponse différente. Peut-être que vous écrivez une bibliothèque populaire qui sera utilisée dans les pare-feu d'entreprise et que vous n'avez pas accès au code d'appel. Ensuite, utilisez l'une des autres bonnes réponses ici. Notez que la bibliothèque populaire jQuery pratique l'encapsulation du son et commence:

(function( window, undefined ) {

Vous seul pouvez répondre à votre question de la manière spécifique que vous recherchez. Que dire de plus?

modifier: p.s. si vous voulez vraiment mon avis, je vous dirai que ce n'est pas dangereux du tout. Tout ce qui serait susceptible de causer des défauts (comme l'attribution à undefined, qui est évidemment un comportement à risque bien documenté) est lui-même un défaut. C'est le défaut qui est le risque. Mais c'est juste dans mes scénarios, où je peux me permettre de garder cette perspective. Comme je vous le recommande, j'ai répondu à la question pour mes cas d'utilisation.

3
shannon

Il est sûr de tester contre indéfini. Comme vous l'avez déjà mentionné. Si vous arrivez à un code qui le remplace (ce qui est hautement améliorable), ne l'utilisez plus.

Peut-être si vous créez une bibliothèque pour un usage public, vous pouvez utiliser certaines des techniques pour éviter que l'utilisateur ne la change. Mais même dans ce cas, c'est leur problème, pas votre bibliothèque.

3
Bart Calixto

Vous pouvez utiliser undefined dans votre code lors du codage pour les navigateurs prenant en charge ECMAScript 5.1 tel quel immuable selon la spécification de langue .

Voir aussi this table de compatibilité ou this caniuse ECMAScript 5 pour voir que tous les navigateurs modernes (IE 9+) ont implémenté undefined immuable.

2
Daniel A. R. Werner

Ce n'est pas dangereux du tout. Il ne peut être écrasé que lorsqu'il fonctionne sur un moteur ES3 et il est peu probable qu'il ne soit plus utilisé.

1
kirk.burleson

Tout d'abord, si votre code casse, ce n'est probablement pas parce qu'un autre développeur là-bas "essaie d'être un imbécile" comme vous le dites.

Il est vrai que undefined n'est pas un mot-clé. Mais c'est c'est une primitive de niveau global. Il était destiné à être utilisé comme ceci (voir "non défini" sur developer.mozilla.org ):

var x;
if (x === undefined) {
    // these statements execute
}
else {
    // these statements do not execute
}

L'alternative commune à cela (également de MDN ) et à mon avis, la meilleure façon est:

// x has not been declared before
if (typeof x === 'undefined') { // evaluates to true without errors
    // these statements execute
}

if(x === undefined){ // throws a ReferenceError

}

Ce qui présente quelques avantages, l'évidence (d'après les commentaires) est qu'elle ne déclenche pas d'exception lorsque x n'est pas déclaré. Il convient également de noter que MDN souligne également qu'il est important d'utiliser === plus de == dans le premier cas car:

var x=null;
if (x === undefined) {
    // this is probably what you meant to do
    // these lines will not execute in this case
}
else if (x == undefined) {
    // these statements will execute even though x *is* defined (as null)
}
else {
    // these statements do not execute
}

C'est une autre raison souvent négligée pour laquelle il est probablement préférable d'utiliser simplement la deuxième alternative dans tous les cas.

Conclusion: Ce n'est pas mal de le coder de la première manière, et certainement pas dangereux. L'argument que vous avez vu que vous utilisez comme exemple contre lui (qu'il peut être remplacé) n'est pas l'argument le plus fort pour coder l'alternative avec typeof. Mais utiliser typeof est plus fort pour une raison en particulier: il ne lève pas d'exception lorsque votre var n'est pas déclarée. On pourrait également faire valoir que l'utilisation de == au lieu de === est une erreur courante, auquel cas il ne fait pas ce que vous attendiez. Alors pourquoi ne pas utiliser typeof?

0
Octopus