386 votes

Sont légitimes il utilise JavaScript ' s « avec » affirmation ?

Alan Tempête de commentaires en réponse à ma réponse concernant l' with déclaration m'a fait réfléchir. J'ai rarement trouvé une raison d'utiliser ce langage, et n'avait jamais beaucoup réfléchi à la façon dont il peut causer des problèmes. Maintenant, je suis curieux de savoir comment je pourrait faire un usage efficace de l' with, tout en évitant ses pièges...

Donc ma question est, où avez-vous trouvé l' with instruction utile?

532voto

Shog9 Points 82052

Une autre utilisation a eu lieu pour moi aujourd'hui, j'ai donc cherché sur le web avec enthousiasme et a trouvé un existant mention: Définition de Variables dans un Bloc de Portée.

Arrière-plan

JavaScript, en dépit de sa ressemblance superficielle avec le C et le C++, n'a pas de portée des variables dans le bloc qu'ils sont définis dans:

var name = "Joe";
if ( true )
{
   var name = "Jack";
}
// name now contains "Jack"

La déclaration d'une fermeture en boucle est une tâche commune où cela peut conduire à des erreurs:

for (var i=0; i<3; ++i)
{
   var num = i;
   setTimeout(function() { alert(num); }, 10);
}

Parce que la boucle for n'introduit pas un nouveau champ d'application, le même num - avec une valeur de 2 - seront partagés par l'ensemble des trois fonctions.

Un nouveau champ d'application: let et with

Avec l'introduction de l' let déclaration en JavaScript 1.7, il devient facile d'introduire un nouveau champ d'application lorsque cela est nécessaire pour éviter ces problèmes:

for (var i=0; i<3; ++i)
{
   // variables introduced in this statement 
   // are scoped to the block following it.
   let (num = i) 
   {
      setTimeout(function() { alert(num); }, 10);
   }
}

Mais jusqu'à ce que les autres navigateurs en œuvre, cela restera limitée à Mozilla code ciblé. Cependant, nous pouvons facilement simuler ce comportement à l'aide de with:

for (var i=0; i<3; ++i)
{
   // object members introduced in this statement 
   // are scoped to the block following it.
   with ({num: i})
   {
      setTimeout(function() { alert(num); }, 10);
   }
}

La boucle fonctionne maintenant comme prévu, la création de trois variables distinctes avec des valeurs de 0 à 2. Notez que les variables déclarées dans le bloc ne sont pas limités à, ce qui est identique au comportement de l' let, mais à la différence du comportement de blocs en C++ (en C, les variables doivent être déclarées au début d'un bloc, donc dans un sens, c'est similaire).

164voto

airportyh Points 7912

J’ai été en utilisant la déclaration sous une forme simple d’importation étendue. Disons que vous avez un générateur de balises de quelque sorte. Plutôt que d’écrire :

Vous pouvez écrire à la place :

Pour ce cas d’utilisation, je ne fais pas toute cession, donc je n’ai pas le problème de l’ambiguïté qui sont associé.

86voto

Alan Storm Points 82442

Comme mes commentaires précédents indiqué, je ne pense pas que vous pouvez utiliser with en toute sécurité quelle que soit la tentation, il pourrait être dans une situation donnée. Étant donné que la question n'est pas directement abordé ici, je vais le répéter. Considérons le code suivant

user = {};
someFunctionThatDoesStuffToUser(user);
someOtherFunction(user);

with(user){
    name = 'Bob';
    age  = 20;
}

Sans l'analyse attentive de ces appels de fonction, il n'y a aucun moyen de savoir quel est l'état de votre programme sera après l'exécution de ce code. Si user.name a déjà été défini, il sera désormais Bob. Si ce n'était pas définie, le global name sera initialisé ou changé d' Bob et de la user objet restera sans name de la propriété.

Les Bugs se produisent. Si vous utilisez avec vous finirez par le faire et d'augmenter les chances de votre programme échoue. Pire, vous risquez de rencontrer code du travail qui définit un mondial dans le bloc, que ce soit délibérément ou par l'intermédiaire de l'auteur de ne pas savoir à propos de ce caprice de la construction. C'est un peu comme la rencontre de l'automne par le biais d'un interrupteur, vous n'avez aucune idée si l'auteur a voulu cela et il n'y a aucun moyen de savoir si "fixation" le code d'introduire une régression.

Langages de programmation modernes sont calées plein de fonctionnalités. Certaines fonctionnalités, après des années d'utilisation, sont découverts à être mauvais, et devrait être évitée. Javascript with est l'un d'entre eux.

71voto

Andy E Points 132925

J'ai effectivement trouvé l' with déclaration incroyablement utiles récemment. Cette technique n'a jamais vraiment eu lieu pour moi jusqu'à ce que j'ai commencé mon projet en cours - une console de ligne de commande écrit en JavaScript. J'essayais d'imiter le Firebug/WebKit console des Api où les commandes peuvent être entrées dans la console mais ils n'ont pas de remplacer toutes les variables dans la portée globale. J'ai pensé à cela en essayant de surmonter un problème que j'ai mentionné dans les commentaires de Shog9 excellente réponse.

Pour obtenir cet effet, j'ai utilisé deux déclarations, de "couche" d'un champ derrière la portée mondiale:

with (consoleCommands) {
    with (window) {
        eval(expression); 
    }
}

La grande chose au sujet de cette technique est que, au-delà de la performance des inconvénients, il ne souffre pas l'habitude des craintes de l' with déclaration, parce que nous sommes dans l'évaluation de la portée globale de toute façon il n'y a pas de danger de variables à l'extérieur de notre pseudo-champ d'être modifiés.

J'ai été inspiré pour écrire cette réponse, lorsque, à ma grande surprise, j'ai réussi à trouver la même technique que celle utilisée ailleurs - le Chrome code source!

InjectedScript._evaluateOn = function(evalFunction, object, expression) {
    InjectedScript._ensureCommandLineAPIInstalled();
    // Surround the expression in with statements to inject our command line API so that
    // the window object properties still take more precedent than our API functions.
    expression = "with (window._inspectorCommandLineAPI) { with (window) { " + expression + " } }";
    return evalFunction.call(object, expression);
}

EDIT: Viens de vérifier le Pyromane de la source, ils ont de la chaîne d'4 avec les états ensemble pour encore plus de couches. Fou!

const evalScript = "with (__win__.__scope__.vars) { with (__win__.__scope__.api) { with (__win__.__scope__.userVars) { with (__win__) {" +
    "try {" +
        "__win__.__scope__.callback(eval(__win__.__scope__.expr));" +
    "} catch (exc) {" +
        "__win__.__scope__.callback(exc, true);" +
    "}" +
"}}}}";

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X