Les commentaires d'Alan Storm en réponse à ma réponse concernant la with
déclaration m'ont fait réfléchir. J'ai rarement trouvé une raison d'utiliser cette fonctionnalité de langue particulière, et je n'avais jamais beaucoup réfléchi à la façon dont cela pourrait causer des problèmes. Maintenant, je suis curieux de savoir comment je pourrais utiliser efficacement with
tout en évitant ses pièges.
Où avez-vous trouvé l' with
énoncé utile?
with
, il n'y a plus rien de tel.Réponses:
Une autre utilisation m'est venue aujourd'hui, alors j'ai fouillé le Web avec enthousiasme et j'en ai trouvé une mention existante: Définir des variables dans l'étendue du bloc .
Contexte
JavaScript, malgré sa ressemblance superficielle avec C et C ++, n'étend pas les variables au bloc dans lequel elles sont définies:
Déclarer une fermeture dans une boucle est une tâche courante lorsque cela peut entraîner des erreurs:
Étant donné que la boucle for n'introduit pas de nouvelle étendue, la même
num
- avec une valeur de2
- sera partagée par les trois fonctions.Une nouvelle portée:
let
etwith
Avec l'introduction de l'
let
instruction dans ES6 , il devient facile d'introduire une nouvelle portée lorsque cela est nécessaire pour éviter ces problèmes:Ou même:
Jusqu'à ce qu'ES6 soit universellement disponible, cette utilisation reste limitée aux navigateurs et développeurs les plus récents désireux d'utiliser des transpilers. Cependant, nous pouvons facilement simuler ce comportement en utilisant
with
:La boucle fonctionne maintenant comme prévu, créant trois variables distinctes avec des valeurs de 0 à 2. Notez que les variables déclarées dans le bloc ne sont pas étendues à celui-ci, contrairement au comportement des blocs en C ++ (en C, les variables doivent être déclarées au début de un bloc, donc en quelque sorte il est similaire). Ce comportement est en fait assez similaire à une
let
syntaxe de bloc introduite dans les versions antérieures des navigateurs Mozilla, mais n'est pas largement adopté ailleurs.la source
for (var i = 0; i < 3; ++i) { setTimeout ((function () { var num = i; return function () { alert (num); }; }) (), 10);}
var toString = function () { return "Hello"; }; with ({"test":1}) { console.log(toString()); };
,. Dans la portée de l' instruction with , toString () est une propriété héritée de Object , donc la fonction explicitement définie n'est pas appelée. Encore une bonne réponse, cependant :-)J'ai utilisé l'instruction with comme une forme simple d'importation à portée limitée. Disons que vous avez un générateur de balisage quelconque. Plutôt que d'écrire:
Vous pouvez plutôt écrire:
Pour ce cas d'utilisation, je ne fais aucune affectation, donc je n'ai pas le problème d'ambiguïté associé à cela.
la source
context.bezierCurveTo
une centaine de fois, vous pouvez direvar bc2 = context.bezierCurveTo;
et ensuite aller àbc2(x,x,etc);
chaque fois que vous voulez l'appeler. C'est assez rapide et encore moins verbeux, alors quewith
c'est super lent.Comme mes commentaires précédents l'ont indiqué, je ne pense pas que vous puissiez l'utiliser en
with
toute sécurité, aussi tentant que cela puisse être dans une situation donnée. Étant donné que le problème n'est pas directement abordé ici, je le répète. Considérez le code suivantSans étudier attentivement ces appels de fonction, il n'y a aucun moyen de savoir quel sera l'état de votre programme après l'exécution de ce code. Si elle
user.name
était déjà définie, elle le sera désormaisBob
. S'il n'a pas été défini, le globalname
sera initialisé ou changé enBob
et l'user
objet restera sansname
propriété.Des bugs se produisent. Si vous utilisez avec vous finirez par le faire et augmenterez les chances d'échec de votre programme. Pire, vous pouvez rencontrer du code de travail qui définit un global dans le bloc with, délibérément ou par le biais de l'auteur ne connaissant pas cette bizarrerie de la construction. C'est un peu comme rencontrer un échec sur un commutateur, vous ne savez pas si l'auteur a voulu cela et il n'y a aucun moyen de savoir si la "correction" du code introduira une régression.
Les langages de programmation modernes regorgent de fonctionnalités. Certaines fonctionnalités, après des années d'utilisation, s'avèrent être mauvaises et doivent être évitées. Javascript
with
est l'un d'entre eux.la source
J'ai trouvé la
with
déclaration incroyablement utile récemment. Cette technique ne m'est jamais venue à l'esprit tant que je n'ai pas commencé mon projet actuel - une console de ligne de commande écrite en JavaScript. J'essayais d'émuler les API de la console Firebug / WebKit où des commandes spéciales peuvent être entrées dans la console mais elles ne remplacent aucune variable dans la portée globale. J'y ai pensé en essayant de surmonter un problème que j'ai mentionné dans les commentaires de l'excellente réponse de Shog9 .Pour obtenir cet effet, j'en ai utilisé deux avec des instructions pour "superposer" une étendue derrière l'étendue globale:
La grande chose à propos de cette technique est que, à part les inconvénients de performances, elle ne souffre pas des craintes habituelles de la
with
déclaration, car nous évaluons de toute façon dans la portée globale - il n'y a aucun danger que des variables en dehors de notre pseudo-portée soient modifié.J'ai été inspiré pour poster cette réponse lorsque, à ma grande surprise, j'ai réussi à trouver la même technique utilisée ailleurs - le code source de Chromium !
EDIT: Je viens de vérifier la source de Firebug, ils enchaînent 4 avec des instructions pour encore plus de couches. Fou!
la source
Oui, oui et oui. Il y a une utilisation très légitime. Regarder:
Fondamentalement, tous les autres crochets DOM ou CSS sont des utilisations fantastiques de with. Ce n'est pas comme si "CloneNode" serait indéfini et reviendrait à la portée globale à moins que vous ne vous y mettiez de côté et décidiez de le rendre possible.
La plainte de Crockford pour la vitesse est qu'un nouveau contexte est créé par avec. Les contextes sont généralement chers. Je suis d'accord. Mais si vous venez de créer un div et que vous n'avez pas de cadre disponible pour configurer votre CSS et que vous devez configurer 15 propriétés CSS à la main, la création d'un contexte sera probablement moins cher que la création de variables et 15 déréférences:
etc...
la source
with
. Cependant, dans ce cas particulier, vous pouvez simplement faire:element.style.cssText="background: black ; color: blue ; border: 1px solid green"
extend
méthode à partir soit jQuery ou Underscore.js:$.extend(element.style, {fontWeight: 'bold', fontSize: '1.5em', color: '#55d', marginLeft: '2px'})
..css()
méthode ...Vous pouvez définir une petite fonction d'assistance pour fournir les avantages
with
sans ambiguïté:la source
with_
étant une version boueuse doublée de(function(_){ _.a="foo"; })(object_here);
(la façon standard de simuler des blocs de style c / java). Utilisez-le à la place.Semble à peine la peine car vous pouvez faire ce qui suit:
la source
with
.Je n'utilise jamais avec, je ne vois pas de raison de le faire et je ne le recommande pas.
Le problème
with
est qu'il empêche de nombreuses optimisations lexicales qu'une implémentation ECMAScript peut effectuer. Étant donné l'essor des moteurs rapides basés sur JIT, ce problème deviendra probablement encore plus important dans un avenir proche.Cela pourrait ressembler à
with
des constructions plus propres (lorsque, par exemple, l'introduction d'une nouvelle portée au lieu d'un wrapper de fonction anonyme commun ou le remplacement d'un aliasing détaillé), mais cela n'en vaut vraiment pas la peine . Outre une baisse des performances, il y a toujours un danger d'attribuer à une propriété d'un mauvais objet (lorsque la propriété n'est pas trouvée sur un objet dans la portée injectée) et peut-être d'introduire à tort des variables globales. IIRC, ce dernier problème est celui qui a motivé Crockford à recommander d'éviterwith
.la source
with(){}
constructions comme celles données dans d'autres réponses ici, dans les navigateurs modernes, j'aimerais voir leur!with(){}
: la configuration d'une nouvelle portée avecwith
est extrêmement coûteuse sur tous les navigateurs que j'ai testés. Vous voudriez éviter cela dans tout code appelé très fréquemment. En outre, Chrome a affiché un succès spectaculaire pour tout code s'exécutant dans unewith()
étendue. Fait intéressant, IE avait les meilleures caractéristiques de performances pour le code dans leswith()
blocs: en tenant compte du coût d'installation,with()
fournit le moyen le plus rapide d'accès des membres dans les machines virtuelles IE6 et IE8 (bien que ces machines virtuelles soient les plus lentes dans l'ensemble).with()
est presque un ordre de grandeur plus lent dans Chrome, et plus de deux fois plus rapide dans IE ...!Visual Basic.NET a une
With
instruction similaire . L'une des façons les plus courantes de l'utiliser est de définir rapidement un certain nombre de propriétés. Au lieu de:, Je peux écrire:
Ce n'est pas seulement une question de paresse. Cela rend également le code beaucoup plus lisible. Et contrairement à JavaScript, il ne souffre pas d'ambiguïté, car vous devez préfixer tout ce qui est affecté par la déclaration par un
.
(point). Ainsi, les deux suivants sont clairement distincts:contre.
Le premier est
someObject.Foo
; ce dernier estFoo
dans le champ d'application extérieursomeObject
.Je trouve que le manque de distinction de JavaScript le rend beaucoup moins utile que la variante de Visual Basic, car le risque d'ambiguïté est trop élevé. En dehors de cela,
with
c'est toujours une idée puissante qui peut améliorer la lisibilité.la source
Vous pouvez utiliser
with
pour introduire le contenu d'un objet en tant que variables locales dans un bloc, comme cela se fait avec ce petit moteur de modèle .la source
L'utilisation de "avec" peut rendre votre code plus sec.
Considérez le code suivant:
Vous pouvez le sécher comme suit:
Je suppose que cela dépend si vous avez une préférence pour la lisibilité ou l'expressivité.
Le premier exemple est plus lisible et probablement recommandé pour la plupart des codes. Mais la plupart du code est assez apprivoisé de toute façon. Le second est un peu plus obscur mais utilise la nature expressive du langage pour réduire la taille du code et les variables superflues.
J'imagine que les gens qui aiment Java ou C # choisiraient la première façon (object.member) et ceux qui préfèrent Ruby ou Python choisiraient cette dernière.
la source
Je pense que l'utilisation évidente est comme raccourci. Par exemple, si vous initialisez un objet, vous enregistrez simplement en tapant beaucoup de "ObjectName". Un peu comme les "with-slots" de lisp qui vous permettent d'écrire
ce qui revient à écrire
Il est plus évident pourquoi c'est un raccourci que lorsque votre langage autorise "Objectname.foo" mais quand même.
la source
with-slots
vous devez spécifier les emplacements que vous utilisez, tandis que vouswith
utiliserez tous les emplacements liés à l'exécution.Ayant de l'expérience avec Delphi, je dirais que l'utilisation avec devrait être une optimisation de taille de dernier recours, éventuellement réalisée par une sorte d'algorithme de minimiseur javascript avec accès à une analyse de code statique pour vérifier sa sécurité.
Les problèmes de portée que vous pouvez rencontrer avec une utilisation libérale de l' instruction with peuvent être une douleur royale dans l'a ** et je ne voudrais pas que quiconque expérimente une session de débogage pour comprendre ce qu'il .. se passe dans votre code , seulement pour découvrir qu'il a capturé un membre d'objet ou la mauvaise variable locale, au lieu de votre variable de portée globale ou externe que vous vouliez.
La déclaration VB with est meilleure, en ce sens qu'elle a besoin des points pour lever l'ambiguïté, mais la déclaration Delphi with est un pistolet chargé avec un déclencheur de cheveux, et il me semble que le javascript est assez similaire pour justifier le même avertissement.
la source
L'utilisation de avec n'est pas recommandée et est interdite en mode strict ECMAScript 5. L'alternative recommandée consiste à affecter l'objet dont vous souhaitez accéder aux propriétés à une variable temporaire.
Source: Mozilla.org
la source
L'instruction with peut être utilisée pour réduire la taille du code ou pour les membres d'une classe privée, par exemple:
L'instruction with est très utile si vous souhaitez modifier la portée, ce qui est nécessaire pour avoir votre propre portée globale que vous pouvez manipuler au moment de l'exécution. Vous pouvez y mettre des constantes ou certaines fonctions d'assistance souvent utilisées comme par exemple "toUpper", "toLower" ou "isNumber", "clipNumber" aso ..
À propos des mauvaises performances que je lis souvent: la portée d'une fonction n'aura aucun impact sur les performances, en fait dans mon FF, une fonction de portée s'exécute plus rapidement qu'une fonction non étendue:
Ainsi, de la manière mentionnée ci-dessus, l'instruction with n'a aucun effet négatif sur les performances, mais elle est bonne car elle diminue la taille du code, ce qui affecte l'utilisation de la mémoire sur les appareils mobiles.
la source
L'utilisation de avec rend également votre code plus lent dans de nombreuses implémentations, car tout est désormais enveloppé dans une portée supplémentaire pour la recherche. Il n'y a aucune raison légitime d'utiliser avec en JavaScript.
la source
var obj={a:0,b:0,c:0};var d=+new Date;with(obj){for(var i=0;i<1000000;++i){a+=1;b+=1;c+=1}}+new Date-d;
donne en moyenne 2500, tandis quevar obj={a:0,b:0,c:0};var d=+new Date;for(var i=0;i<1000000;++i){obj.a+=1;obj.b+=1;obj.c+=1}+new Date-d;
donne en moyenne 750, ce qui rend celui qui est utilisé plus de 3 fois plus lentement.with
code et 903 sans. Avec cette petite différence, même dans une boucle serrée, je ferais une sélection basée sur la simplicité du codage et la facilité de refactorisation au cas par cas avant de se soucier des performances.Je pense que la déclaration with peut être utile lors de la conversion d'un langage de modèle en JavaScript. Par exemple JST en base2 , mais je l'ai vu plus souvent.
Je suis d'accord que l'on peut programmer cela sans la déclaration with. Mais parce qu'il ne pose aucun problème, c'est une utilisation légitime.
la source
C'est bon pour mettre du code qui s'exécute dans un environnement relativement compliqué dans un conteneur: je l'utilise pour créer une liaison locale pour "window" et pour exécuter du code destiné à un navigateur Web.
la source
Je pense que l'utilisation littérale de l'objet est intéressante, comme un remplacement direct pour l'utilisation d'une fermeture
ou la déclaration with équivalente à une clôture
Je pense que le vrai risque est de minipuler accidentellement des variables qui ne font pas partie de l'instruction with, c'est pourquoi j'aime que le littéral d'objet soit passé avec, vous pouvez voir exactement ce que ce sera dans le contexte ajouté dans le code.
la source
J'ai créé une fonction de «fusion» qui élimine une partie de cette ambiguïté avec la
with
déclaration:Je peux l'utiliser de la même manière
with
, mais je peux savoir que cela n'affectera aucune portée que je n'ai pas l'intention d'affecter.Usage:
la source
Pour certains éléments de code courts, je voudrais utiliser les fonctions trigonométriques comme
sin
,cos
etc. en mode degré plutôt qu'en mode radiant. Pour cela, j'utilise unAngularDegree
objet:Ensuite, je peux utiliser les fonctions trigonométriques en mode degré sans autre bruit de langage dans un
with
bloc:Cela signifie: j'utilise un objet comme un ensemble de fonctions, que j'active dans une région de code limitée pour un accès direct. Je trouve cela utile.
la source
with
instruction de cette façon, cela rend le code difficile à lire parce que vous ne savez pas quelle fonction est globale et quelle fonction est appelée dans la portée de with object, donc si une fonction n'est pas définie dans le portée de l'objet puis il essaiera d'y accéder dans l'espace de noms globalz = Math.atan2( Math.sin(d * Math.PI / 180), Math.cos( pol.lat * Math.PI / 180) * Math.tan( pos.lat * Math.PI / 180 ) - Math.sin( pol.lat * Math.PI / 180 ) * Math.cos( d * Math.PI / 180) ) * 180 / Math.PI;
donnerait le même résultat, mais c'est l'horreur.with
qui vous rendraient perplexe.Je pense que l'utilité de
with
peut dépendre de la qualité de l' écriture de votre code. Par exemple, si vous écrivez du code qui ressemble à ceci:alors vous pourriez faire valoir que
with
cela améliorera la lisibilité du code en procédant comme suit:À l'inverse, on pourrait faire valoir que vous violez la loi de Déméter , mais, encore une fois, peut-être pas. Je m'égare =).
Par-dessus tout, sachez que Douglas Crockford recommande de ne pas utiliser
with
. Je vous invite à consulter son article de blog concernantwith
et ses alternatives ici .la source
Je ne vois vraiment pas en quoi l'utilisation de with est plus lisible que de simplement taper object.member. Je ne pense pas que ce soit moins lisible, mais je ne pense pas que ce soit plus lisible non plus.
Comme l'a dit lassevk, je peux certainement voir comment utiliser avec serait plus sujet aux erreurs que d'utiliser simplement la syntaxe très explicite "object.member".
la source
Vous avez pu voir la validation d'un formulaire en javascript sur W3schools http://www.w3schools.com/js/js_form_validation.asp où le formulaire d'objet est "scanné" pour trouver une entrée avec le nom "email"
Mais je l'ai modifié pour obtenir de TOUT formulaire tous les champs valident comme non vides, quel que soit le nom ou la quantité de champ dans un formulaire. Eh bien, je n'ai testé que des champs de texte.
Mais le with () a simplifié les choses. Voici le code:
la source
Le fork Coco de CoffeeScript a un
with
mot - clé, mais il définit simplementthis
(également accessible en écriture comme@
dans CoffeeScript / Coco) à l'objet cible dans le bloc. Cela supprime l'ambiguïté et atteint la conformité du mode strict ES5:la source
Voici une bonne utilisation pour
with
: ajouter de nouveaux éléments à un objet littéral, en fonction des valeurs stockées dans cet objet. Voici un exemple que je viens d'utiliser aujourd'hui:J'avais un ensemble de tuiles possibles (avec des ouvertures orientées vers le haut, le bas, la gauche ou la droite) qui pouvaient être utilisées, et je voulais un moyen rapide d'ajouter une liste de tuiles qui seraient toujours placées et verrouillées au début du jeu. . Je ne voulais pas continuer à taper
types.tbr
pour chaque type de la liste, alors je viens de l'utiliserwith
.la source
Vous pouvez utiliser avec pour éviter d'avoir à gérer explicitement l'arity lors de l'utilisation de require.js:
Implémentation de requirejs.declare:
la source
Comme Andy E l'a souligné dans les commentaires de la réponse de Shog9, ce comportement potentiellement inattendu se produit lors de l'utilisation
with
avec un objet littéral:Pas que ce comportement inattendu ne soit déjà une caractéristique de
with
.Si vous voulez vraiment encore utiliser cette technique, utilisez au moins un objet avec un prototype nul.
Mais cela ne fonctionnera que dans ES5 +. N'utilisez pas non plus
with
.la source
Je travaille sur un projet qui permettra aux utilisateurs de télécharger du code afin de modifier le comportement de certaines parties de l'application. Dans ce scénario, j'ai utilisé une
with
clause pour empêcher leur code de modifier quoi que ce soit en dehors de la portée avec laquelle je veux qu'ils s'amusent. La partie (simplifiée) du code que j'utilise pour ce faire est:Ce code garantit (quelque peu) que le code défini par l'utilisateur n'a accès à aucun objet de portée globale tel que
window
ni à aucune de mes variables locales via une fermeture.Juste pour dire aux sages, je dois encore effectuer des vérifications de code statiques sur le code soumis par l'utilisateur pour s'assurer qu'ils n'utilisent pas d'autres manières sournoises pour accéder à la portée mondiale. Par exemple, le code défini par l'utilisateur suivant accède directement à
window
:la source
ma
se résume à
Pouvez-vous faire confiance à un code de si faible qualité? Non, nous voyons que cela a été rendu absolument illisible. Cet exemple prouve incontestablement qu'il n'y a pas besoin de with-statement, si je prends bien la lisibilité;)
la source