2009-11-04 2 views
4

Je trouve toujours le mot-clé with un peu ... énigmatique.Des exemples d'un exemple non-trivial et utile du mot clé 'with'?

En bref, with se comporte comme:

with (obj) { 
    // do stuff 
} 

Cela ajoute obj à la tête de la chaîne de portée et exécute ensuite le avec bloc. Lorsque le bloc est terminé, il supprime obj de la tête de la chaîne de portée.

Selon MDC, cela vous permet de faire des choses comme

var a, x; 
var r = 10; 
with(Math) { 
    a = PI * r * r; 
    x = r * cos(PI/2); 
} 

Je peux référencer des propriétés de Math - comme PI - directement, sans dire Math.PI. Ce qui est bien, mais plutôt inutile.

Quelqu'un peut-il fournir un exemple d'utilisation intéressante de with?

+0

duplication possible de [Existe-t-il des utilisations légitimes de la déclaration "with" de JavaScript?] (Http://stackoverflow.com/questions/61552/are-there-legitimate-uses-for-javascripts-with-statement) – Shog9

Répondre

5

Une alternative à la norme solution de fermeture utilisant des fonctions à l'intérieur d'une boucle for:

<a href="#">blah</a><br> 
<a href="#">blah</a><br> 
<a href="#">foo</a><br> 
<script> 
    (function() { 
    var anchors = document.getElementsByTagName('a'); 
     for (var i = anchors.length; i--;) { 
      var link = anchors[i]; 
      with ({ number: i }) { 
       link.onclick = function() { 
        alert(number); 
       }; 
      } 
     } 
    })(); 
</script> 

Crédit nlogax pour fournir une solution que je à peu près arnaquer: Javascript infamous Loop issue?

Voici la solution standard:

<script> 
    (function() { 
    var anchors = document.getElementsByTagName('a'); 
    for (var i = anchors.length; i--;) { 
     var link = anchors[i]; 
     (function(i) { 
      link.onclick = function() { 
       alert(i) 
      } 
     })(i); 
    } 
    })(); 
</script> 
+0

Pouvez-vous s'il vous plaît fournir la version de la solution de fermeture standard pour la comparaison? – ntownsend

+0

Oh, aussi ... très soigné! – ntownsend

+0

fait - ouais c'est. –

1

L'instruction with dans JS est similaire à l'instruction with dans VB.net. C'est simplement un moyen d'éviter la répétition avec les propriétés/méthodes d'un objet. Par exemple, supposons qu'un contrôle d'étiquette est en cours de modification en fonction d'un événement/d'une action. Ce contrôle d'étiquette a des propriétés telles que FontColor, CssClass, visibilité, etc.

au lieu de l'écriture programmeur:

myLabel.FontColor=Color.Blue 
myLabel.CSSClass="SomeCSSClass" 
myLabel.Visiblity=True 
myLabel.Text = "Hello World" 

Nous pouvons raccourcir ce à:

With myLabel 
    .Text = "Hello World" 
    .FontColor = Color.Blue 
    .CssClass="SomeCSSClass" 
    .Visibility=True 
End With 
+2

l'instruction JavaScript présente de sérieux inconvénients, contrairement à l'instruction VB. –

+0

@Konrad, s'il vous plaît élaborer. – ntownsend

4

Il faut dire ici que la déclaration with en JavaScript est largement désapprouvée.

Voir le document With Statement Considered Harmful de Douglas Crockford.

Je ne peux pas le dire mieux que lui (sérieusement, cliquez sur le lien), mais en bref si vous faites ceci:

with (mySuperLongObjectReferenceThatIHateTyping) { 
    propertyAlpha = 'a'; 
    propertyBeta = 2; 
    propertyGamma = false; 
} 

Vous ne pouvez pas savoir en regardant ce code si vous Affectez des valeurs aux propriétés de l'objet mySuperLongObjectReferenceThatIHateTyping ou de l'objet global (fenêtre).

Crockford recommande ceci:

var o = mySuperLongObjectReferenceThatIHateTyping; 
o.propertyAlpha = 'a'; 
o.propertyBeta = 2; 
o.propertyGamma = false; 

Ce qui est sans ambiguïté. Ou vous pouvez même utiliser une fonction de sorte que vous avez portée et de ne pas créer une autre variable globale:

(function(o) { 
    o.propertyAlpha = 'a'; 
    o.propertyBeta = 2; 
    o.propertyGamma = false; 
})(mySuperLongObjectReferenceThatIHateTyping); 
+2

La citation: "Si vous ne pouvez pas lire un programme et être sûr que vous savez ce qu'il va faire, vous ne pouvez pas avoir confiance que cela va fonctionner correctement. devrait être évité." – artlung

2

Je l'utilise régulièrement pour ajouter plusieurs propriétés CSS à un objet style, par exemple

with(document.body.style) { 
    color = 'green'; 
    background = 'red'; 
} 

également , Je l'ai utilisé at least once pour affecter les propriétés d'un objet à des variables locales sans avoir à stocker une référence à l'objet lui-même.

Il est également une alternative à la fermeture lorsque vous voulez prendre un « instantané » de la valeur d'une variable:

var foo = []; 
for(var i = 10; i--;) 
    with({ i : i }) foo[i] = function() { document.writeln(i); }; 

// prints 0..9 
for(var i = 0; i < foo.length; ++i) 
    foo[i](); 

Gardez à l'esprit que with peut sérieusement affecter la performance que la chaîne de prototype de l'objet ajouté à l'environnement lexical doit être vérifié en premier lors de la résolution d'un nom de variable.

1

Je n'ai pas d'expérience en Javascript, je commence à peine à comprendre comment l'utiliser, donc mon opinion ne devrait pas avoir le même poids que celle d'une personne expérimentée dans la langue spécifique. Je serais intéressé par les réponses à mon idée.

J'ai expérimenté avec un style de définition d'objets de type classe qui dépend de l'instruction Javascript avec. Je soumets que c'est un usage légitime. Chaque objet semblable à une classe dans ce style fonctionne comme une fabrique pour que les objets répondent à un objectif.

Ce style n'utilise pas le ce mot clé dans les méthodes d'instance. Ce style conçoit que chaque objet généré à partir d'un de ces objets de type classe doit avoir un aspect public et un aspect privé. Un objet Javascript représente chacun de ces aspects. Les détenteurs de références à l'objet se réfèrent uniquement à l'aspect public. Les méthodes, cependant, connaissent les deux aspects et je l'implémente avec des fermetures. Je ne prétends pas que ce style est applicable aux cas où nous nous soucions beaucoup du temps d'exécution ou des performances de la mémoire. Je sacrifie délibérément un peu de chacun d'entre eux à l'efficacité de la programmation. Je m'attends à trouver beaucoup de cas où je veux programmer quelque chose rapidement et avec peu de chance d'erreur, et où les demandes à l'exécution ne seront pas critiques. Depuis que j'ai essayé le code dans un navigateur plutôt que node.js, une considération pratique de l'environnement de développement pour moi est que les erreurs de syntaxe dans un grand fichier source peuvent être difficiles à cerner et à corriger. Je résout ce problème en ajoutant du code par petits incréments. Par conséquent, je souhaite que les objets de type classe puissent accepter une définition de méthode d'instance à la fois, plutôt que d'exiger que toutes les définitions de méthode apparaissent dans un fichier source.

Je déclare un objet de type classe sans aucune méthode d'instance, et je place l'objet de type classe dans l'espace de noms dans lequel je suis programmé.

Puis j'appelle l'objet de type classe à plusieurs reprises à une méthode appelée "init" et chaque fois, je passe un initialiseur, une fonction à appeler lors de l'initialisation d'une instance. Finalement, lorsque je commence à utiliser l'objet de type classe comme une fabrique pour ses instances, chaque fois que je lui demande une nouvelle instance, il crée les aspects public et privé pour l'instance, lie l'aspect privé à l'instance publique, appelle ensuite tous les initialiseurs qui ont été définis, en leur passant l'aspect privé de la nouvelle instance. Dans mon style, chaque attribut public est une méthode. Toutes les variables dont les valeurs ne seront pas des fonctions doivent vivre du côté privé.

Une chose qu'un initiateur peut faire est d'établir une variable du côté privé.

Une autre chose qu'un initiateur peut faire est d'ajouter une méthode du côté public ou privé.

L'ordre est important pour l'exécution des initialiseurs - l'objet de type classe est requis pour les exécuter dans le même ordre que celui dans lequel ils ont été définis. Par conséquent, chaque initialiseur peut compter sur les aspects publics et privés de l'instance ayant les attributs qui ont été établis par les initialiseurs précédents. Pour le programmeur, cela crée en effet une paire d'étendues lexicales, puisque les initialiseurs ne sont pas établis par un code conditionnel ou dynamique d'aucune sorte; ils sont établis au fur et à mesure que les fichiers sources sont exécutés par le navigateur juste après leur lecture et leur analyse. Maintenant, dans certaines langues, en particulier le langage Ruby et le langage Self, vous pouvez écrire un identifiant nu et l'interpréter comme un appel de méthode sur l'objet courant. Donc, dans Ruby, "foo" peut signifier "self.foo" et dans Self, "foo" peut signifier "self foo" (la syntaxe de l'appel de méthode diffère entre ces langages, mais jusqu'au niveau de détail auquel je parle de la sémantique maintenant, "self.foo" dans Ruby et "self foo" dans Self sont les mêmes). Cette abréviation hors de "self" est particulièrement pratique pour appeler des méthodes privées et des variables d'instance. Le langage Javascript ne fournit pas cette commodité.

Dans les contextes dans une méthode d'instance où je veux utiliser un attribut du côté privé ou public pour sa valeur (notez, pas du côté gauche d'une affectation), j'aime la commodité de se référer à l'attribut par juste son nom et ne pas avoir à écrire "vars". ou "soi". à gauche de la localiser (j'utilise "vars" pour l'aspect privé et "self" pour l'aspect public). Pour cette raison, j'enveloppe chaque initialiseur dans une instruction Javascript avec. Cela me semble légitime, car dans mon style, la population de l'objet ciblé est établie lexicalement. Pour voir les attributs, le programmeur doit seulement regarder les initialiseurs fournis plus tôt dans les fichiers source vers le même objet semblable à une classe (qui est lui-même identifié par son nom dans le code source, donc pour le logiciel, nous pouvons le considérer comme une entité lexicale, même si aucun analyseur Javascript ne le détecte).