Valutazione del cortocircuito per fare solo il primo di un certo numero di azioni

3

Quindi ho letto valutazione del cortocircuito, è male pratica? , È una cattiva pratica usare la valutazione di cortocircuito invece di una clausola if? e alcune altre domande correlate, e capisco che è generalmente considerata una cattiva pratica usare la valutazione di cortocircuito per il controllo di flusso .

Sto provando a scrivere senza avvisi, ROC (Really Obvious Code), e sto cercando il modo migliore per fare solo il primo di una serie di azioni che restituiscono un valore di verità.

Il codice di cui sto effettuando il refactoring era in origine così:

this.initSingleTag(tags.open_at === '7', CombinedSearch.ITEMS.avail_morning, 'search-functions-open', 'morning') ||
this.initSingleTag(tags.open_at === '12', CombinedSearch.ITEMS.avail_midday, 'search-functions-open', 'midday') ||
this.initSingleTag(tags.open_at === '18', CombinedSearch.ITEMS.avail_evening, 'search-functions-open', 'evening') ||
this.initSingleTag(tags.open_at === '22', CombinedSearch.ITEMS.avail_late, 'search-functions-open', 'late');

Cercando di liberarlo dagli avvertimenti in JSHint, il mio refactor di prima esecuzione assomiglia a:

if (!this.initSingleTag(tags.open_at === '7', CombinedSearch.ITEMS.avail_morning, 'search-functions-open', 'morning')) {
   if (!this.initSingleTag(tags.open_at === '12', CombinedSearch.ITEMS.avail_midday, 'search-functions-open', 'midday')) {
     if (!this.initSingleTag(tags.open_at === '18', CombinedSearch.ITEMS.avail_evening, 'search-functions-open', 'evening')) {
       this.initSingleTag(tags.open_at === '22', CombinedSearch.ITEMS.avail_late, 'search-functions-open', 'late');
     }
   }
 }

Che sinceramente non mi sembra più leggibile. Esiste una pratica migliore comune per questo tipo di situazione?

Modifica: dopo aver postato un po 'la domanda e un po' di headscratch, mi sono reso conto che:

CombinedSearch.prototype.initFirstTruthyTag = function(tags) {
    var that = this;
    $.each(tags, function(i, parameters) {
        return !(that.initSingleTag.apply(that, parameters));
    });
};

... Più tardi ...

this.initFirstTruthyTag([
    [tags.open_at === '7', CombinedSearch.ITEMS.avail_morning, 'search-functions-open', 'morning'],
    [tags.open_at === '12', CombinedSearch.ITEMS.avail_midday, 'search-functions-open', 'midday'],
    [tags.open_at === '18', CombinedSearch.ITEMS.avail_evening, 'search-functions-open', 'evening'],
    [tags.open_at === '22', CombinedSearch.ITEMS.avail_late, 'search-functions-open', 'late']
]);

Anche se sono dolorosamente consapevole del fatto che il terzo parametro viene ripetuto più volte, è una sorta di linea laterale rispetto alla domanda originale (in più non sono sicuro che la conformità con DRY sia superiore alla coerenza con la chiamata alla funzione originale, che è ancora usato in tutto il resto del codice attorno a questa chiamata)

    
posta Chris O'Kelly 22.02.2017 - 07:06
fonte

3 risposte

6

Che dire di qualcosa sulla falsariga di

var tagCombiList = [['7',CombinedSearch.ITEMS.avail_morning, 'morning'],
                    ['12',CombinedSearch.ITEMS.avail_midday, 'midday'],
                    ...]

for(t of tagCombiList)
{
    if(this.initSingleTag(tags.open_at === t[0],t[1],'search-functions-open', t[3]) 
       break;
}

Il vantaggio di questo codice non solo evita la necessità di cortocircuiti. È anche molto più ASCIUTTO: in entrambe le versioni, è stata ripetuta quasi la stessa riga di codice quattro volte. Inoltre, separando la combinazione di dati tabulari dei dati di input dal codice che effettivamente utilizza i dati, si ha una migliore separazione delle preoccupazioni, che come "effetto collaterale" richiede meno colonne, il che migliora anche leggibilità.

    
risposta data 22.02.2017 - 08:17
fonte
4

La versione in cortocircuito potrebbe non essere il pezzo di codice più bello ma certamente non è neanche terribile. strongmente consiglio comunque di formattarlo in modo diverso,

Guardando questo codice, non è immediatamente chiaro cosa sta succedendo.

this.initSingleTag(tags.open_at === '7', CombinedSearch.ITEMS.avail_morning, 'search-functions-open', 'morning') ||
this.initSingleTag(tags.open_at === '12', CombinedSearch.ITEMS.avail_midday, 'search-functions-open', 'midday') ||
this.initSingleTag(tags.open_at === '18', CombinedSearch.ITEMS.avail_evening, 'search-functions-open', 'evening') ||
this.initSingleTag(tags.open_at === '22', CombinedSearch.ITEMS.avail_late, 'search-functions-open', 'late');

Questa versione - che è identica tranne che per lo spazio bianco - è molto più chiara.

this.initSingleTag(tags.open_at === '7', CombinedSearch.ITEMS.avail_morning, 'search-functions-open', 'morning')
    || this.initSingleTag(tags.open_at === '12', CombinedSearch.ITEMS.avail_midday, 'search-functions-open', 'midday')
    || this.initSingleTag(tags.open_at === '18', CombinedSearch.ITEMS.avail_evening, 'search-functions-open', 'evening')
    || this.initSingleTag(tags.open_at === '22', CombinedSearch.ITEMS.avail_late, 'search-functions-open', 'late');

Generalmente ritengo che l'uso dello spazio bianco sia principalmente una questione di gusti, ma non così in questo caso.

Le altre due risposte hanno già indicato che il tuo codice è in realtà un'iterazione che si arresta al primo elemento per il quale initSingleTag restituisce true quindi sono d'accordo che un ciclo (o, preferibilmente, una combinazione lenta di any e map se la tua tecnologia lo supporta) dovrebbe essere usato qui.

Se la logica non può essere formulata come un ciclo - ad esempio, perché stai chiamando funzioni diverse ogni volta e le funzioni non sono cittadini di prima classe nella tua lingua - allora nota che c'è un'altra alternativa agli operatori di cortocircuito e lo stile freccia nidificato if cascade.

if (firstStrategy(...)) {
} else if (secondStrategy(...)) {
} else if (thirdStrategy(...)) {
} else {
    this.isNotYourLuckyDay(...);
}

Tecnicamente, questo è ancora un% co_de nidificato ma molto più bello da guardare. Usare i rendimenti iniziali sarebbe ancora un'altra alternativa.

if (firstStrategy(...)) {
    return;
}
if (secondStrategy(...)) {
    return;
}
if (thirdStrategy(...)) {
    return;
}
this.isNotYourLuckyDay(...);
    
risposta data 22.02.2017 - 09:46
fonte
2

Se vuoi creare un codice più leggibile puoi:

a.- Crea un dizionario con le coppie chiave / valore per CombinedSearchItems .

b.- Crea un altro metodo / funzione per chiamare initSingleTag come rimuovere il codice duplicato.

c.- Suddividi le condizioni if .

CombinedSearchItemsDict = {
  'morning': CombinedSearch.ITEMS.avail_morning,
  'midday': CombinedSearch.ITEMS.avail_midday, 
  'evening': CombinedSearch.ITEMS.avail_evening, 
  'late': CombinedSearch.ITEMS.avail_late 
}

cond1 = magicFunction(7, 'morning')
cond2 = !cond1 && magicFunction(12, 'midday')
cond3 = !cond1 && !cond2 && magicFunction(18, 'evening')
if (!cond3) {
       magicFunction(22, 'late')
}

function magicFunction(time, day_time)
{
  timeStr = str(time)
  combinedSearch = CombinedSearchItemsDict[day_time] 

  return this.initSingleTag(tags.open_at === time, combinedSearch, 'search-functions-open', day_time)
}

... ma come puoi vedere è ancora difficile da capire. La chiave è creare codice che sarà facile da leggere per qualcuno in futuro ... (che qualcuno può essere te stesso) ..

Voglio dire, se qualcuno legge 'magicFunction' non c'è nulla su quel nome che dice cosa sta succedendo!

Quindi, invece di usare un nome enigmatico come magicFunction, dovresti usare un nome che descriva cosa stai facendo all'interno di quella funzione. Lo stesso per cond1 , cond2 e cond3 , un altro nome come morningTagSuccess , middayTagSuccess e eveningTagSuccess possono dare più informazioni su cosa sta succedendo, ma ancora ...

Forse più importante, devi chiedertelo, Cosa sto cercando di fare? e Perché? Stai cercando di fare qualcosa con la forza bruta? Perché stai cercando di vedere "Se non ho successo, prova un'altra cosa?" Perché non verificare prima quale caso devi eseguire in base ai tuoi parametri / stato del sistema? Qualcosa di simile a;

if (isTagValid('morning'))
{
    applySingleTag(7, 'morning')
}
else if (isTagValid('midday'))
{
    applySingleTag(12, 'midday')
}
else if (isTagValid('evening'))
{
    applySingleTag(18, 'evening')
}
else
{
    applySingleTag(22, 'late')
}

Sì, non stiamo usando il cortocircuito, ma forse questo non è il posto giusto per farlo.

    
risposta data 22.02.2017 - 08:17
fonte

Leggi altre domande sui tag