Assegnare una variabile nella dichiarazione della condizione if, buona pratica o no? [chiuso]


113

Sono passato un anno fa dai classici linguaggi OO come Java a JavaScript. Il codice seguente è decisamente sconsigliato (o addirittura non corretto) in 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;
}

Fondamentalmente ho appena scoperto che posso assegnare una variabile a un valore in un'istruzione if condition e controllare immediatamente il valore assegnato come se fosse booleano.

Per una scommessa più sicura, di solito lo separo in due righe di codice, prima assegno quindi controllo la variabile, ma ora che ho trovato questo, mi chiedo solo se è una buona pratica o meno agli occhi degli sviluppatori JavaScript esperti?


"The following code is definitely not recommended (or event not correct) in Java..."È corretto anche in JavaScript? Perché, per quanto posso vedere, restituisci un intero ( return parseInt(...)) se dayNumber != -1è vero, ma un booleano se è falso.
Daniel Kvist

Risposte:


117

Non lo consiglierei. Il problema è che sembra un errore comune in cui si tenta di confrontare i valori, ma si utilizza un singolo =invece di ==o ===. Ad esempio, quando vedi questo:

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

non sai se è quello che intendevano fare, o se intendevano scrivere questo:

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

Se vuoi davvero svolgere il compito sul posto, ti consiglio di fare anche un confronto esplicito:

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

1
@ Matthew Crumley: questo risponde alla mia domanda in modo chiaro. Non sto controllando assegnando ma controllando qualunque valore ritenga essere dopo l'assegnazione. Questa comprensione è giusta?
Michael Mao

1
@ Michael: sì, è corretto. L'aggiunta del confronto fondamentalmente rende le tue intenzioni più chiare.
Matthew Crumley

4
L'ultimo esempio non funziona, tuttavia, se stai testando il fallimento / successo di una funzione che restituisce un valore booleano. In altre parole, mentre if (resultArr = myNeedle.exec(myHaystack)) {...}funziona, if ((resultArr = myNeedle.exec(myHaystack)) === true) {...}non lo fa perché l'assegnazione a resultArr è sempre veritiera anche quando la funzione result non lo è. Se qualcuno usa questo costrutto .., ricordarsi di dichiarare prima la variabile risultato; 'var' non è legale all'interno dell'istruzione if condition.
Ville

3
Puoi usare if (!!(value = someFunction())), ma come hai detto, il problema è che non puoi usare varall'interno ifquindi finisci per creare un globale o non ottieni nulla poiché devi comunque dichiarare valuein una riga separata. Peccato, mi è piaciuta molto questa costruzione in C ++.
riv

1
@riv, hai ragione; nel caso in cui la funzione restituisca un booleano - come ho detto nel mio commento sopra - allora il condizionale funziona come previsto. Ma se la funzione restituisce un booleano (come nel mio esempio), l'intero costrutto è in qualche modo non sensato; chiaramente la mia linea di pensiero era - a giudicare dall'esempio - che la funzione avrebbe restituito un array. Un test rapido indica che la condizione truerestituisce solo quando la funzione ritorna true, ma in tutti gli altri casi (incluso quando viene restituito un array, una stringa, un numero o un null) restituisce false.
Ville

28

Non vedo alcuna prova che non sia una buona pratica. Sì, può sembrare un errore, ma è facile rimediare con commenti giudiziosi. Prendiamo ad esempio:

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

Perché quella funzione dovrebbe essere autorizzata a essere eseguita una seconda volta con:

alert(processorIntensiveFunction());

Perché la prima versione sembra brutta? Non posso essere d'accordo con questa logica.


32
Non per tirare fuori un vecchio commento, ma non sono d'accordo con i tuoi argomenti. Il codice leggibile dovrebbe spiegare se stesso senza la necessità di un commento: l'aggiunta di un commento a un codice confuso non è un rimedio. Per quanto riguarda la seconda parte, che dice che l'alternativa è chiamare di nuovo la funzione, non credo che nessuno abbia intenzione di farlo. Invece lo farestix = processorItensiveFunction(); if(x) { alert(x); }
maksim

9
@maksim: mi piace il codice leggibile, ma questo non significa necessariamente che il codice debba essere stupido o troppo prolisso. Distribuire le cose su più righe e destreggiarsi tra i valori può effettivamente portare a un codice peggiore. Il codice inserito può avere effetti collaterali imprevisti in un linguaggio debolmente digitato / flessibile come JS. L'assegnazione in un'istruzione condizionale è valida in javascript, perché stai solo chiedendo "se l'assegnazione è valida, fai qualcosa che possibilmente includa il risultato dell'assegnazione". Ma in effetti, anche l'assegnazione prima del condizionale è valida, non troppo prolissa e più comunemente usata.
okdewit

1
@maksim perché pensi che if ( ! x = anyFunction() )non sia leggibile? Non necessita di alcun commento.
JDrake

Se aggiusti OPC, lavori con altri sviluppatori di diversi livelli di abilità (in altre parole, sei un professionista) odierai che questo sia anche possibile.
davidjmcclelland

2
@maksim - anche la tua soluzione sarebbe molto scomoda in una if-elsesituazione. Considera: il if (condition) {...} else if (x = processorIntensiveFunction()) {alert(x)} tuo precedente x = processorIntensiveFunction();sarebbe uno sforzo inutile se l'iniziale conditionfosse vera.
Adrian Bartholomew

16

L'ho fatto molte volte. Per bypassare l'avviso JavaScript, aggiungo due parentesi:

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

Dovresti evitarlo, se vuoi davvero usarlo, scrivi un commento sopra di esso dicendo cosa stai facendo.


1
@SHiNKiROU: come posso vedere gli avvisi javascript? Esiste un compilatore Javascript? o l'interprete genererà una sorta di avvertimento? Uso sempre la console Firefox come nel debug di javascript ma non vedo mai output simili. Mi dispiace per la mia esperienza limitata.
Michael Mao

5
@Michael: JSLint ( jslint.com ) è un popolare programma / libreria che controlla i programmi JavaScript per possibili errori o codice non valido .
Matthew Crumley

Usa Mozilla Firefox con l'estensione Firebug e / o Web Developer per controllare gli avvisi.
Ming-Tang

L'ho appena provato con if ((a = [1, 2]).length > 0) { console.log(a); }where anon è ancora inizializzato da nessuna parte e in effetti ha funzionato (bello! Rende molto più semplice l'uso di regex). È corretto che non ho bisogno di niente di var|const|letqui? Sai dove potrei leggere di più su questo trucco ?
t3chb0t

4

Puoi farlo anche in Java. E no, non è una buona pratica. :)

(E usa ===Javascript per l'uguaglianza digitata. Leggi il libro The Good Parts di Crockford su JS.)


@quixoto: posso fare questo trucco in Java? Mi chiedo ... non ho jdk a mano, quindi non sono in grado di ottenere un codice di esempio in Java. Dalla mia scarsa memoria, Java ti darà solo un errore di runtime se il valore restituito valuta qualcosa di non booleano come in un'istruzione condizionale, giusto?
Michael Mao

1
Ah, sì, in Java viene controllato il tipo per essere un tipo booleano. Ma puoi farloif (foo = getSomeBoolValue()) { }
Ben Zotto

si, è esatto. una variabile booleana per verificare se qualcosa è riuscito e un'altra variabile per memorizzare il valore restituito. È così che Java fa il suo lavoro, lo conosco troppo bene quindi mi sento strano nel vedere che Javascript può fare due cose in una semplice riga :)
Michael Mao

@BenZotto non è una buona pratica perché? "Per evitare un uso improprio accidentale di una variabile, di solito è una buona idea introdurre la variabile nel più piccolo ambito possibile. In particolare, di solito è meglio ritardare la definizione di una variabile finché non si può darle un valore iniziale ... Una delle applicazioni più eleganti di questi due principi è dichiarare una variabile in un condizionale. " - Stroustrup, "The C ++ Programming Language".
JDrake

1
Ciao, sono venuto qui come utente javascript node.js. Perché non è una buona pratica in un caso con cui ho avuto problemi: if (myvar = 'just a test') Crea una variabile GLOBAL node.js myvar ( nodejs.org/docs/latest-v12.x/api/globals.html #globals_global ). Quindi, se sei come me e hai utilizzato quella variabile nella gestione delle richieste del server (tornandoci dopo pochi secondi quando altre richieste potrebbero essere arrivate e cose del genere), puoi rimanere sorpreso dai risultati che ottieni. Quindi la raccomandazione è: Tieni presente che questo modello crea una variabile globale in node.js.
pein-consulting.de

4

C'è un caso in cui lo fai, con while-loops.
Durante la lettura dei file, di solito ti piace questo:

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
        }
    }
}

Guarda il whileciclo alla riga 9. Lì, una nuova riga viene letta e memorizzata in una variabile, quindi viene eseguito il contenuto del ciclo. So che questa non è ifun'affermazione, ma immagino che anche un ciclo while possa essere incluso nella tua domanda.

La ragione di ciò è che quando si utilizza a FileInputStream, ogni volta che si chiama FileInputStream.readLine(), legge la riga successiva nel file, quindi se l'avessi chiamata dal ciclo fileIn.readLine() != nullsenza assegnare la variabile, invece di chiamare (currentLine = fileIn.readLine()) != null, e poi la chiamassi da anche all'interno del ciclo, otterrai solo una riga su due.

Spero tu capisca e buona fortuna!


3

È anche possibile eseguire assegnazioni all'interno di istruzioni if ​​in Java. Un buon esempio sarebbe leggere qualcosa e scriverlo:

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

Il codice:

// 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: grazie per questo esempio. Non sono davvero un professionista né in Java né in javascript ... È bene sapere che questo approccio è fattibile anche in Java :)
Michael Mao

Non ne vedo il punto. Puoi farlo in Java, PHP e molti altri linguaggi. La domanda riguardava Javascript.
pmrotule

No, non è necessariamente, devi rileggere attentamente la domanda.
Nitrodist

3

Se dovessi fare riferimento al libro di Martin Fowlers Refactoring che migliora il design del codice esistente ! Poi ci sono diversi casi in cui sarebbe una buona pratica, ad es. condizionali lunghi e complessi per utilizzare una chiamata di funzione o metodo per affermare il tuo caso:

"Motivazione

Una delle aree più comuni di complessità in un programma risiede nella complessa logica condizionale. Mentre scrivi codice per testare le condizioni e per fare varie cose a seconda delle varie condizioni, ti ritroverai rapidamente con un metodo piuttosto lungo. La lunghezza di un metodo è di per sé un fattore che rende più difficile la lettura, ma le condizioni aumentano la difficoltà. Il problema di solito sta nel fatto che il codice, sia nella verifica delle condizioni che nelle azioni, ti dice cosa succede ma può facilmente oscurare il motivo per cui accade.

Come con qualsiasi blocco di codice di grandi dimensioni, è possibile rendere più chiara la propria intenzione scomponendola e sostituendo blocchi di codice con una chiamata al metodo che prende il nome dall'intenzione di quel blocco di codice. > Con le condizioni puoi ricevere ulteriori vantaggi facendo ciò per la parte condizionale e ciascuna delle alternative. In questo modo si evidenzia la condizione e si rende chiaramente> su cosa si sta ramificando. Evidenzia anche il motivo della ramificazione ".

E sì, la sua risposta è valida anche per le implementazioni Java. Non assegna la funzione condizionale a una variabile sebbene negli esempi.


1

Non è una buona pratica. Presto ti confonderai. Sembra simile a un errore comune: uso improprio degli operatori "=" e "==".

Dovresti suddividerlo in 2 righe di codici. Non solo aiuta a rendere il codice più chiaro, ma anche facile da refactoring in futuro. Immagina di cambiare la condizione IF? Potresti rimuovere accidentalmente la riga e la tua variabile non riceverà più il valore assegnato.


@thethanghn: è esattamente quello di cui ho paura. quando divento più grande e pigro, semplicemente non voglio digitare di più nel codice se un minor numero di sequenze di tasti sarà sufficiente :)
Michael Mao

1
No, non mi confondo e lo faccio sempre. Ci sono dei vantaggi.
JDrake

Dipende davvero, no? Se provieni da un background in "C" (e altri linguaggi basati su C), il costrutto è molto familiare e le alternative sono molto scomode. IMO, è qualcosa che si impara una volta e poi si sa. Non è qualcosa su cui inciamperai più di una volta.
Max Waterman,

0

Lo considererei più uno stile C della vecchia scuola; non è davvero una buona pratica in JavaScript, quindi dovresti evitarlo.


8
Non lo considero nemmeno una buona pratica in C.
Matthew Crumley

1
Lo considero una buona pratica in molte lingue.
JDrake

Solo dire "non è una buona pratica" non è abbastanza, imo. Si tratta solo di educazione: si impara una volta, e basta.
Max Waterman,

0

potresti fare qualcosa del genere:

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

0

Sono venuto qui da Golang, dove è comune vedere qualcosa di simile

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

In cui errè limitato solo a quel ifblocco. In quanto tale, ecco cosa sto facendo in es6, che sembra piuttosto brutto, ma non fa lamentare le mie regole di eslint piuttosto rigide e ottiene lo stesso.

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

Le parentesi graffe extra definiscono un nuovo, uh, "ambito lessicale"? Il che significa che posso usare conste errnon è disponibile per il blocco esterno.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.