Attribuer une variable dans si la déclaration de condition, bonne pratique ou non? [fermé]


113

Il y a un an, je suis passé des langages OO classiques tels que Java à JavaScript. Le code suivant n'est certainement pas recommandé (ou même pas correct) en Java:

if(dayNumber = getClickedDayNumber(dayInfo))
{
    alert("day number found : " + dayNumber);
}
function getClickedDayNumber(dayInfo)
{
    dayNumber = dayInfo.indexOf("fc-day");
    if(dayNumber != -1) //substring found
    {
        //normally any calendar month consists of "40" days, so this will definitely pick up its day number.
        return parseInt(dayInfo.substring(dayNumber+6, dayNumber+8));
    }
    else return false;
}

Fondamentalement, je viens de découvrir que je peux attribuer une variable à une valeur dans une instruction de condition if et vérifier immédiatement la valeur attribuée comme si elle était booléenne.

Pour un pari plus sûr, je sépare généralement cela en deux lignes de code, attribuez d'abord puis vérifiez la variable, mais maintenant que j'ai trouvé cela, je me demande simplement si c'est une bonne pratique ou non aux yeux des développeurs JavaScript expérimentés?


"The following code is definitely not recommended (or event not correct) in Java..."Est-ce même correct en JavaScript? Parce que, pour autant que je puisse voir, vous retournez un entier ( return parseInt(...)) si dayNumber != -1est vrai, mais un booléen s'il est faux.
Daniel Kvist

Réponses:


117

Je ne le recommanderais pas. Le problème est que cela ressemble à une erreur courante où vous essayez de comparer des valeurs, mais utilisez un seul =au lieu de ==ou ===. Par exemple, lorsque vous voyez ceci:

if (value = someFunction()) {
    ...
}

vous ne savez pas si c'est ce qu'ils voulaient faire, ou s'ils avaient l'intention d'écrire ceci:

if (value == someFunction()) {
    ...
}

Si vous voulez vraiment faire la tâche sur place, je vous recommande également de faire une comparaison explicite:

if ((value = someFunction()) === <whatever truthy value you are expecting>) {
    ...
}

1
@Matthew Crumley: cela répond à ma question de manière claire. Je ne vérifie pas en attribuant, mais en vérifiant quelle que soit la valeur évaluée après l'affectation. Cette compréhension est-elle juste?
Michael Mao

1
@Michael: oui, c'est correct. L'ajout de la comparaison rend simplement vos intentions plus claires.
Matthew Crumley

4
Le dernier exemple ne fonctionne pas, cependant, si vous testez l'échec / le succès d'une fonction qui renvoie un booléen. En d'autres termes, bien que if (resultArr = myNeedle.exec(myHaystack)) {...}fonctionne, if ((resultArr = myNeedle.exec(myHaystack)) === true) {...}pas parce que l'affectation à resultArr est toujours véridique même lorsque le résultat de la fonction ne l'est pas. Si quelqu'un utilise cette construction .., n'oubliez pas de déclarer d'abord la variable de résultat; 'var' n'est pas légal dans l'instruction de condition if.
Ville

3
Vous pouvez utiliser if (!!(value = someFunction())), mais comme vous l'avez dit, le problème est que vous ne pouvez pas utiliser à l' varintérieur, ifdonc vous finissez par créer un global, ou ne réalisez rien comme vous devez de toute façon déclarer valuedans une ligne séparée. Dommage, j'ai vraiment aimé cette construction en C ++.
riv

1
@riv, vous avez raison; au cas où la fonction renvoie un booléen - comme je l'ai dit dans mon commentaire ci-dessus - alors le conditionnel fonctionne comme prévu. Mais si la fonction renvoie un booléen (comme dans mon exemple) alors la construction entière est en quelque sorte non sensique; clairement ma ligne de pensée était - à en juger par l'exemple - que la fonction renverrait un tableau. Un test rapide indique que la condition est évaluée trueuniquement lorsque la fonction trueest renvoyée, mais dans tous les autres cas (y compris lorsqu'un tableau, une chaîne, un nombre ou une valeur nulle est renvoyée), elle est évaluée false.
Ville

28

Je ne vois aucune preuve que ce n'est pas une bonne pratique. Oui, cela peut ressembler à une erreur, mais cela est facilement corrigé par des commentaires judicieux. Prenons par exemple:

if (x = processorIntensiveFunction()) { // declaration inside if intended
    alert(x);
}

Pourquoi cette fonction devrait-elle être autorisée à s'exécuter une deuxième fois avec:

alert(processorIntensiveFunction());

Parce que la première version a l'air mauvais? Je ne peux pas être d'accord avec cette logique.


32
Pas pour déterrer un vieux commentaire, mais je ne suis pas d'accord avec vos arguments. Le code lisible doit s'expliquer sans avoir besoin d'un commentaire - l'ajout d'un commentaire à un code déroutant n'est pas un remède. Quant à la deuxième partie, qui dit que l'alternative est d'appeler à nouveau la fonction, je ne pense pas que quiconque ait l'intention de le faire. Au lieu de cela, vous feriezx = processorItensiveFunction(); if(x) { alert(x); }
maksim

9
@maksim: J'aime le code lisible, mais cela ne signifie pas nécessairement que le code doit être simplifié ou trop détaillé. Répartir les choses sur plusieurs lignes et jongler avec les valeurs entre les variables peut en fait conduire à un code pire. Le code inséré peut avoir des effets secondaires imprévus dans un langage faiblement typé / flexible comme JS. L'affectation dans une instruction conditionnelle est valide en javascript, car vous demandez simplement "si l'affectation est valide, faites quelque chose qui inclut éventuellement le résultat de l'affectation". Mais en effet, l'assignation avant le conditionnel est également valide, pas trop verbeuse et plus couramment utilisée.
okdewit

1
@maksim pourquoi pensez-vous que ce if ( ! x = anyFunction() )n'est pas lisible? Il n'a besoin d'aucun commentaire.
JDrake

Si vous corrigez OPC, travaillez avec d'autres développeurs de différents niveaux de compétence (en d'autres termes, vous êtes un professionnel), vous détesterez que cela soit même possible.
davidjmcclelland

2
@maksim - votre solution serait également très gênante dans une if-elsesituation. Considérez- if (condition) {...} else if (x = processorIntensiveFunction()) {alert(x)} votre préalable x = processorIntensiveFunction();serait un effort inutile si l'initiale conditionétait vraie.
Adrian Bartholomew

16

Je l'ai fait plusieurs fois. Pour contourner l'avertissement JavaScript, j'ajoute deux parens:

if ((result = get_something())) { }

Vous devriez l'éviter, si vous voulez vraiment l'utiliser, écrivez un commentaire dessus en disant ce que vous faites.


1
@SHiNKiROU: comment voir les avertissements javascript? Existe-t-il un compilateur Javascript? ou l'interprète va générer une sorte d'avertissement? J'utilise la console Firefox comme dans le débogage javascript tout le temps mais je ne vois jamais de sorties similaires. Désolé pour mon expérience limitée.
Michael Mao

5
@Michael: JSLint ( jslint.com ) est un programme / bibliothèque populaire qui vérifie les programmes JavaScript pour d'éventuelles erreurs ou un mauvais code.
Matthew Crumley

Utilisez Mozilla Firefox avec Firebug et / ou l'extension Web Developer pour vérifier les avertissements.
Ming-Tang

Je viens de l'essayer avec if ((a = [1, 2]).length > 0) { console.log(a); }an'est encore initialisé nulle part et cela a en effet fonctionné (bien! Rend l'utilisation de regex beaucoup plus facile). Est-ce exact que je n'en ai pas besoin d' var|const|letici? Savez-vous où je pourrais en savoir plus sur cette astuce ?
t3chb0t

4

Vous pouvez également le faire en Java. Et non, ce n'est pas une bonne pratique. :)

(Et utilisez le ===en Javascript pour l'égalité typée. Lisez le livre The Good Parts de Crockford sur JS.)


@quixoto: Puis-je faire cette astuce en Java? Je me demande ... Je n'ai pas jdk à la main, donc je ne peux pas obtenir un exemple de code en Java. De ma mauvaise mémoire, Java vous obtiendra simplement une erreur d'exécution si la valeur de retour évalue quelque chose de non booléen comme dans une instruction conditionnelle, non?
Michael Mao

1
Ah, oui, en Java, le type est vérifié pour être un type booléen. Mais vous pouvez le faireif (foo = getSomeBoolValue()) { }
Ben Zotto

Oui c'est vrai. une variable booléenne pour tester si quelque chose a réussi et une autre variable pour stocker la valeur renvoyée. C'est comme ça que Java fait son travail, je suis trop familier avec ça, donc je me sens étrange de voir que Javascript peut faire deux choses en une seule ligne :)
Michael Mao

@BenZotto ce n'est pas une bonne pratique pourquoi? "Pour éviter une mauvaise utilisation accidentelle d'une variable, il est généralement judicieux d'introduire la variable dans la plus petite portée possible. En particulier, il est généralement préférable de retarder la définition d'une variable jusqu'à ce que l'on puisse lui donner une valeur initiale ... L'une des applications les plus élégantes de ces deux principes est de déclarer une variable dans un conditionnel. " - Stroustrup, "Le langage de programmation C ++".
JDrake

1
Salut, je suis venu ici en tant qu'utilisateur javascript node.js. Pourquoi là, ce n'est pas une bonne pratique dans un cas avec lequel j'ai eu du mal: if (myvar = 'just a test') Crée une variable GLOBAL node.js myvar ( nodejs.org/docs/latest-v12.x/api/globals.html #globals_global ). Donc, si vous êtes comme moi et que vous avez utilisé cette variable dans la gestion des requêtes du serveur (y revenir après quelques secondes lorsque d'autres requêtes ont pu tomber, etc.), vous pouvez être surpris des résultats que vous obtenez. La recommandation est donc la suivante: sachez que ce modèle crée une variable globale dans node.js.
pein-consulting.de

4

Il y a un cas où vous le faites, avec while-loops.
Lors de la lecture de fichiers, vous faites généralement comme ceci:

void readFile(String pathToFile) {
    // Create a FileInputStream object
    FileInputStream fileIn = null;
    try {
        // Create the FileInputStream
        fileIn = new FileInputStream(pathToFile);
        // Create a variable to store the current line's text in
        String currentLine;
        // While the file has lines left, read the next line,
        // store it in the variable and do whatever is in the loop
        while((currentLine = in.readLine()) != null) {
            // Print out the current line in the console
            // (you can do whatever you want with the line. this is just an example)
            System.out.println(currentLine);
        }
    } catch(IOException e) {
        // Handle exception
    } finally {
        try {
            // Close the FileInputStream
            fileIn.close();
        } catch(IOException e) {
            // Handle exception
        }
    }
}

Regardez le while-loop à la ligne 9. Là, une nouvelle ligne est lue et stockée dans une variable, puis le contenu de la boucle est exécuté. Je sais que ce n'est pas une ifdéclaration, mais je suppose qu'une boucle while peut également être incluse dans votre question.

La raison en est que lors de l'utilisation de a FileInputStream, chaque fois que vous appelez FileInputStream.readLine(), il lit la ligne suivante du fichier, donc si vous l'auriez appelé à partir de la boucle avec juste fileIn.readLine() != nullsans affecter la variable, au lieu d'appeler (currentLine = fileIn.readLine()) != null, puis l' avez appelé à partir de à l'intérieur de la boucle aussi, vous n'obtiendrez qu'une ligne sur deux.

J'espère que vous comprenez, et bonne chance!


3

Vous pouvez également effectuer des affectations dans les instructions if en Java. Un bon exemple serait de lire quelque chose et de l'écrire:

http://www.exampledepot.com/egs/java.io/CopyFile.html?l=new

Le code:

// Copies src file to dst file.
// If the dst file does not exist, it is created
void copy(File src, File dst) throws IOException 
{
    InputStream in = new FileInputStream(src);
    OutputStream out = new FileOutputStream(dst);

    // Transfer bytes from in to out
    byte[] buf = new byte[1024];
    int len;
    while ((len = in.read(buf)) > 0) {
        out.write(buf, 0, len);
    }
    in.close();
    out.close();
}

@Nitrodist: merci pour cet exemple. Je ne suis vraiment pas pro ni en Java ni en javascript ... Il est bon de savoir que cette approche est également réalisable en Java :)
Michael Mao

Je ne vois pas l'intérêt de cela. Vous pouvez le faire en Java, PHP et de nombreux autres langages. La question portait sur Javascript.
pmrotule

Non, ce n'est pas nécessairement le cas, vous devez relire la question attentivement.
Nitrodist

3

Si vous deviez vous référer au livre de Martin Fowlers Refactoring améliorant la conception du code existant ! Ensuite, il y a plusieurs cas où ce serait une bonne pratique, par exemple. conditionnelles longues et complexes pour utiliser un appel de fonction ou de méthode pour affirmer votre cas:

"Motivation

L'un des domaines de complexité les plus courants d'un programme réside dans la logique conditionnelle complexe. Lorsque vous écrivez du code pour tester les conditions et pour faire diverses choses en fonction de diverses conditions, vous vous retrouvez rapidement avec une méthode assez longue. La longueur d'une méthode est en elle-même un facteur qui la rend plus difficile à lire, mais les conditions augmentent la difficulté. Le problème réside généralement dans le fait que le code, à la fois dans les vérifications de conditions et dans les actions, vous dit ce qui se passe mais peut facilement obscurcir pourquoi cela se produit.

Comme pour tout gros bloc de code, vous pouvez rendre votre intention plus claire en la décomposant et en remplaçant des morceaux de code par un appel de méthode nommé d'après l'intention de ce bloc de code. > Avec des conditions, vous pouvez bénéficier d'un avantage supplémentaire en faisant cela pour la partie conditionnelle et chacune des alternatives. De cette façon, vous mettez en évidence la condition et faites clairement ce sur quoi vous vous branchez. Vous mettez également en évidence la raison de la ramification. "

Et oui, sa réponse est également valable pour les implémentations Java. Il n'affecte pas la fonction conditionnelle à une variable dans les exemples.


1

Ce n'est pas une bonne pratique. Vous serez bientôt confus à ce sujet. Cela ressemble à une erreur courante: une mauvaise utilisation des opérateurs "=" et "==".

Vous devez le diviser en 2 lignes de codes. Cela permet non seulement de rendre le code plus clair, mais également de le refactoriser à l'avenir. Imaginez que vous modifiez la condition IF? Vous pouvez accidentellement supprimer la ligne et votre variable ne reçoit plus la valeur qui lui est attribuée.


@thethanghn: c'est exactement ce dont j'ai peur. quand je vieillis et que je suis paresseux, je ne veux tout simplement pas taper plus dans le code si moins de frappes suffiront :)
Michael Mao

1
Non, je ne suis pas confus et je le fais tout le temps. Il y a des avantages à cela.
JDrake

Cela dépend vraiment, n'est-ce pas? Si vous venez d'un arrière-plan 'C' (et d'autres langages basés sur C), alors la construction est très familière, et les alternatives sont très maladroites. OMI, c'est quelque chose qui s'apprend une fois et ensuite vous savez. Ce n'est pas quelque chose sur lequel vous trébucherez plus d'une fois.
Max Waterman

0

Je considérerais cela plus comme un style C à l'ancienne; ce n'est pas vraiment une bonne pratique en JavaScript, vous devriez donc l'éviter.


8
Je ne considère pas non plus cela comme une bonne pratique en C.
Matthew Crumley

1
Je considère que c'est une bonne pratique dans de nombreuses langues.
JDrake

Il ne suffit pas de dire «pas une bonne pratique», imo. C'est vraiment juste une question d'éducation - c'est appris une fois, et c'est tout.
Max Waterman

0

vous pouvez faire quelque chose comme ceci:

if (value = /* sic */ some_function()){
  use_value(value)
}

0

Je suis venu ici du golang, où il est courant de voir quelque chose comme

if (err := doSomething(); err != nil) {
    return nil, err
}

Dans lequel errest limité à ce ifbloc uniquement. En tant que tel, voici ce que je fais dans es6, qui semble assez moche, mais ne fait pas pleurnicher mes règles d'eslint plutôt strictes, et réalise la même chose.

{
  const err = doSomething()
  if (err != null) {
    return (null, err)
  }
}

Les accolades supplémentaires définissent une nouvelle, euh, "portée lexicale"? Ce qui signifie que je peux utiliser constet que je ne suis errpas disponible pour le bloc externe.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.