it-swarm.com.de

Eine if/else-Anweisung vereinfachen?

Ich versuche folgendes zu vereinfachen:

function handleDirection(src) {
  if (src === 'left') {
    if (inverse) {
      tracker--;
    } else {
      tracker++;
    }
  } else {
    if (inverse) {
      tracker++;
    } else {
      tracker--;
    }
  }
}

um die Anzahl der Bedingungen zu reduzieren. Die src wird immer 'left' oder 'right' sein.

28

Sie können das Ergebnis der ersten Prüfung überprüfen.

Dies ist eine exklusive OR Prüfung.

// typeof inverse === 'boolean'

function handleDirection(src) {
    if (src === 'left' === inverse) {
        tracker--;
    } else {
        tracker++;
    }
}

Die Prüfung wertet den Ausdruck in dieser Reihenfolge aus (src === 'left') === inverse:

src === 'left' === inverse
---- first ---             returns a boolean value
--------- second --------- take result of former check & compairs it with another boolean
48
Nina Scholz
function handleDirection(src) {
   var movement = 1;
   if(src === 'left')
     movement = -1;

   if(inverse)
     tracker += movement;
   else
     tracker -= movement;
}
18
Alays

Sie können es sogar mit nur einer Codezeile machen:

function getDirectionOffset(src) {
  tracker += (src === 'left' ? 1 : -1) * (inverse ? -1 : 1);
}
11
Leuronics

Dies könnte zu einem ternären Ausdruck vereinfacht werden, der je nach Zustand 1 oder -1 zurückgibt. Dann können Sie das einfach zur tracker hinzufügen.

function handleDirection(src) {
  var delta = (src === 'left' && inverse) || (src !== 'left' && !inverse) ? -1 : 1;
  tracker += delta;
}

Dies könnte dann anhand der Logik, auf die @NinaScholz in ihrer Antwort hingewiesen hat, weiter vereinfacht werden:

function handleDirection(src) {
  var delta = (src === 'left') === inverse ? -1 : 1;
  tracker += delta;
}
7
Rory McCrossan

Angenommen, inverse ist ein Flag, das Sie einmal gesetzt haben. Dann müssen Sie es nicht jedes Mal berücksichtigen. Sie können die Auswirkung einmal berechnen und es einfach so verwenden, wie es ist. Dadurch werden Ihre Code-Verzweigungen reduziert und Logik. Wenn Sie es im Laufe der Zeit ändern möchten, müssen Sie möglicherweise die Logik für die Berechnung trennen, um sie erneut verwenden zu können.

Sie können die Bewegungsrichtung dann auch in eine eigenständige Funktion extrahieren und Ihre handleDirection wird sehr einfach - Sie berechnen die Richtung, in die Sie gehen möchten, basierend auf src und der invert.

let tracker = 0;

//extract logic for the movement offset based on direction
function getDirectionOffset(src) {
  return src === 'left' ? 1 : -1;
}

//have a setter for the invert property
function setInverse(isInverse) {
  movementModifier = isInverse ? -1 : 1
}

//declare the variable dependent on the inverse property
let movementModifier;

//initialise movementModifier variable
setInverse(false);

function handleDirection(src) {
  const offset = getDirectionOffset(src) * movementModifier;
  
  tracker += offset;
}


// usage
setInverse(true);

handleDirection("left");
handleDirection("left");
handleDirection("right");

console.log(tracker);

Nachdem dies gesagt wurde, deutet dies alles darauf hin, dass Sie eine Funktion nicht verwenden sollten, oder Sie sollten sie anders verwenden. Sie können alle diese Funktionen in einer Klasse sammeln oder stattdessen alle Informationen um Funktionen herumleiten lassen, sodass Sie keine globalen Werte haben. Hier ist ein Beispiel für eine objektorientierte Implementierung des Konzepts:

class TrackerMover {
  constructor(inverse) {
    this.tracker = 0;
    this.movementModifier = inverse ? 1 : -1
  }
  
  handleDirection(src) {
   const offset = this.getDirectionOffset(src) * this.movementModifier;

    this.tracker += offset;
  }
  
  getDirectionOffset(src) {
    return src === 'left' ? -1 : 1;
  }
  
  getPosition() {
    return this.tracker;
  }
}


//usage
const mover = new TrackerMover(true);

mover.handleDirection("left");
mover.handleDirection("left");
mover.handleDirection("right");

console.log(mover.getPosition())

Eine weitere Alternative ist, die Bewegung NICHT jedes Mal zu berechnen. Sie wissen tatsächlich jedes Mal, was passiert. In der Tat haben Sie eine Wahrheitstabelle, in der Ihre Eingaben src === left und inverse sind und die Ausgaben die Art sind, wie Sie Ihr Tracking ändern.

+--------+------------+--------+
| isLeft | isInverted | Offset |
+--------+------------+--------+
| true   | true       |     -1 |
| true   | false      |      1 |
| false  | true       |      1 |
| false  | false      |     -1 |
+--------+------------+--------+

Sie können diese Tabelle also einfach einfügen. 

let tracker = 0;
let invert = false;

const movementLookupTable = {
  "true": { },
  "false": { },
}

//it can be initialised as part of the above expression but this is more readable
movementLookupTable[true ][true ] = -1;
movementLookupTable[true ][false] = 1;
movementLookupTable[false][true ] = 1;
movementLookupTable[false][false] = -1;

function handleDirection(src) {
  const offset = movementLookupTable[src === "left"][invert];

  tracker += offset;
}


// usage
invert = true;

handleDirection("left");
handleDirection("left");
handleDirection("right");

console.log(tracker);

In diesem Fall kann es sich um einen Overkill handeln, dieser Ansatz kann jedoch nützlich sein, wenn mehr Flags (einschließlich values ​​ für die Flags) und/oder Endzustände vorhanden sind. Beispielsweise möchten Sie vielleicht vier Richtungen einführen, den tracker-Wert jedoch nicht ändern, wenn er up oder down ist. 

+-----------+------------+--------+
| direction | isInverted | Offset |
+-----------+------------+--------+
| left      | true       |     -1 |
| left      | false      |      1 |
| right     | true       |      1 |
| right     | false      |     -1 |
| up        | false      |      0 |
| up        | true       |      0 |
| down      | false      |      0 |
| down      | true       |      0 |
+-----------+------------+--------+

Wie Sie sehen, sind es jetzt nicht mehr nur Booleans, sondern Sie können mit jedem Wert umgehen. Wenn Sie eine Tabelle verwenden, ändern Sie auch invert in etwas wie windDirection. Wenn also die Bewegung left ist und die windDirectionright ist, ist das Ergebnis so, wie es jetzt ist, aber Sie könnten die Richtung von left haben und left bewegen Sie weiter. Oder Sie können up bewegen und die Windrichtung ist left, so dass tracker (an diesem Punkt die X-Koordinaten) tatsächlich geändert werden.

+-----------+---------------+---------+
| direction | windDirection | OffsetX |
+-----------+---------------+---------+
| left      | right         |      -1 |
| left      | up            |       1 |
| left      | down          |       1 |
| left      | left          |       2 |
| right     | up            |      -1 |
| right     | down          |      -1 |
| right     | right         |      -2 |
| right     | left          |       1 |
| up        | up            |       0 |
| up        | down          |       0 |
| up        | left          |       1 |
| up        | right         |      -1 |
| down      | up            |       0 |
| down      | down          |       0 |
| down      | left          |       1 |
| down      | right         |      -1 |
+-----------+---------------+---------+

Mit vier Richtungen und vier Windrichtungen, die berücksichtigt werden müssen, kann die Logik für das Lesen und Warten in der Zukunft ziemlich ärgerlich sein. Wenn Sie nur eine Nachschlagetabelle haben, ist dies einfach und Sie können diese Funktion leicht erweitern, um sogar Diagonalen zu handhaben (nehmen wir an, dass dies der Fall ist Sie ändern den Wert um 0.5 anstelle von 1) und Ihr Algorithmus würde sich nicht wirklich darum kümmern, solange Sie nur die Werte aus der Tabelle abrufen.

4
VLAZ

Sie brauchen überhaupt keine if-Sätze. Dieselbe Operation kann ausgeführt werden, indem .__ ein positives oder negatives Inkrement in Abhängigkeit von src und invers Berechnet wird, und zwar nur mit Hilfe des ternären Operators.

function handleDirection(src) {
    tracker += (src == "left" ? 1 : -1) * (inverse ? -1 : 1);
};

Übrigens Aus Gründen der Effizienz würde ich empfehlen, direkt numerische Inkremente/Dekremente anstelle von Zeichenfolgen zu verwenden, für die eine zusätzliche Verarbeitung erforderlich ist Decodiert werden. Sie können Konstanten verwenden, um dieselbe Lesbarkeit zu erreichen:

Auch invers kann als numerischer Wert optimiert werden, der zwischen 1 (nicht Invertiert) und -1 (invertiert) umschaltet.

const left = 1;
const right = -1;
var direction = 1;

function handleDirection(src) {
    tracker += src * direction;
}

function reverse() { // (Example)
    direction = direction * -1;
}

... selbst wenn "rechte" und "linke" Schlüsselwörter von einer Art Textbenutzer-Eingabe stammen, können Sie sie einfach aus einem Wörterbuch übersetzen:

const steps = {
    left = 1;
    right = -1;
};

function handleDirection(src) {
    tracker += steps[src] * direction;
}
3
bitifet

Sie möchten den Tracker erhöhen, wenn src == left oder inverse wahr ist, aber nicht der andere, und den Wert andernfalls verringern, was der Operator "XOR" ^ tut:

function handleDirection(src) {
    if (src === 'left' ^ inverse) {
        tracker++;
    } else {
        tracker--;
    }
}

Sie können das weiter reduzieren, indem Sie einen ternären Ausdruck verwenden:

function handleDirection(src) {
    tracker += src === 'left' ^ inverse ? 1 : -1;
}

Oder wenn Sie jede Art von Bedingung mit impliziten Besetzungen und "intelligenter" Arithmetik vermeiden wollen:

function handleDirection(src) {
    tracker += 1 - 2 * (src === 'right' ^ inverse); // either 1-0=1 or 1-2=-1
}
3
Aaron

Dies hat nur eine Bedingung, und ich finde, dass es intuitiver liest als die anderen Antworten:

function handleDirection(src) {
    if (
        ((src === 'left') && !inverse) ||
        ((src === 'right') && inverse)
    ) {
        tracker++;
    }
    else {
        tracker--;
    }
}
3
Paul S

Ich mag else nicht und versuche, wenn möglich, ein Nest zu vermeiden. Ich denke, das vermittelt die Idee von inverse auf natürlichere Weise:

function handleDirection(src) 
{
    let change = 1;

    if ('right' == src)
        change = -1;

    if (inverse)
        change = -change;

    tracker += change;
}
2
Džuris

Sie können Kurzschluss-Syntax oder ternäre Operatoren verwenden 

// by using short circuiting
    function handleDirection(src) {
       if (src == 'left') tracker = inverse && tracker-1 || tracker +1
       else  tracker = inverse && tracker+1 || tracker -1
    }
// by using ternary operator
 function handleDirection(src) {
       if (src == 'left') tracker = inverse ? tracker-1 : tracker +1
       else  tracker = inverse ? tracker+1 : tracker -1
    }
2
Komal Bansal

Ich weiß, dass dies die Frage nicht direkt mit einer direkten "Vereinfachung" anspricht, aber ich möchte Ihnen eine Antwort geben, die mehrere Probleme der Codequalität anspricht und gleichzeitig den Code besser lesbar macht.

Über Nebenwirkungen

Zuallererst mutiert diese gegebene Funktion externe Werte. Dies führt das Problem von Nebenwirkungen ein:

  • Die Funktion ändert den externen Status, der möglicherweise nicht in der externen Umgebung verarbeitet wird. Dies kann zu undefiniertem Verhalten führen.
  • Die Funktion selbst ist dann an den externen Zustand gebunden, was es schwierig macht, Code zu ändern und neu zu faktorisieren.

Es ist auch viel schwieriger, eine solche Funktion zu testen, da Sie zuerst die Statusumgebung erstellen müssen, um den Test auszuführen.

Ein erster einfacher Tweak wäre, alle externen Werte per Parameter akzeptieren zu lassen und einfach entweder einen 1 oder -1 Wert zurückzugeben, der einem beliebigen Wert zugewiesen ist (in Ihrem Fall tracker).

Exklusiv-oder Bedingungen mit Strings

Zweitens kann die Verwendung eines if/else für String-Werte mit exclusive oder zu einem undefinierten Zustand führen, in dem src etwas anderes als 'right' sein kann, die Funktion sich jedoch so verhält, als wäre es 'right'. Stattdessen sollte es eine Ausnahme auslösen. Die Verwendung eines Schalters ist hier eine gute Hilfe.

Anwenden dieser Punkte auf die Funktion

Wenn die obigen Punkte berücksichtigt werden, würde die Gesamtfunktion folgendermaßen aussehen:

function handleDirection (src, inverse) {
  switch (src) {
    case 'left':
      return inverse ? -1 :  1
    case 'right':
      return inverse ?  1 : -1
    default:
      throw new Error(`Unknown src: ${src}`)
  }
}

und Sie könnten diese Funktion leicht testen:

handleDirection('left' , true)  // -1
handleDirection('left' , false) //  1
handleDirection('right', true)  //  1
handleDirection('right', false) // -1
handleDirection('middle',true)  // Error: Unknown src: middle

Jetzt ist die Funktion deutlich von tracker entkoppelt (denken Sie an Ihre wertvolle Zeit beim Refactoring), aber es ist auch völlig klar, was die Funktion tut.

Hinweis

Zusammenfassend wollte ich betonen, dass es nicht immer darum geht, den einfachsten Code mit den wenigsten Zeilen zu schreiben, sondern Code, der klar zu lesen/verstehen und zu verstehen ist pflegen. Es ist nicht so kurz wie viele der angebotenen Lösungen, aber jeder sollte sofort verstehen, was es tut.

0
Jankapunkt

Sie vergleichen gerade die Saiten, die ich nicht empfehlen würde. Wenn Sie beispielsweise 'Left' anstelle von 'Left' verwenden, schlägt die erste if-Anweisung fehl. Vielleicht kann hier ein Boolean hilfreich sein, da Sie nur zwei Zustände haben können.

Die if -Anweisungen können über bedingte Operatoren komprimiert werden.

Vielleicht suchen Sie nach etwas wie diesem:

function handleDirection(src) {
  if (src) {
    inverse ? tracker-- : tracker++;
  } else {
    inverse ? tracker++ : tracker--;
  }
}

Siehe: https://jsfiddle.net/9zr4f3nv/

0
MagicLegend