Упростить вложенный if/else с повторяющимися результатами?

Я пытаюсь упростить следующее:

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

уменьшить количество условных выражений. src всегда будет 'left' или 'right'.

Ответ 1

Вы можете проверить с результатом первой проверки.

Это эксклюзивная проверка ИЛИ.

// typeof inverse === 'boolean'

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

Проверка вычисляет выражение в следующем порядке (src=== 'left') === inverse:

src === 'left' === inverse
---- first ---             returns a boolean value
--------- second --------- take result of former check & compairs it with another boolean

Ответ 2

function handleDirection(src) {
   var movement = 1;
   if(src === 'left')
     movement = -1;

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

Ответ 3

Вы даже можете сделать это только с одной строкой кода:

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

Ответ 4

Это можно упростить до троичного выражения, которое возвращает 1 или -1 зависимости от состояния. Тогда вы можете просто добавить это в tracker.

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

Это можно затем упростить, используя логику, на которую @NinaScholz указала в своем ответе:

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

Ответ 5

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

оба условия проверяют inverse - с тем же успехом можно использовать это в качестве основного фокуса и использовать src, чтобы определять, следует ли -- или ++ использовать троичные операторы.

Ответ 6

Предполагая, что inverse - это флаг, который вы устанавливаете один раз, тогда вам не нужно каждый раз принимать его во внимание, вы можете рассчитать его влияние один раз и просто использовать его как есть, что сократит ваши ветки кода и логику. Если вы хотите изменить его по мере продвижения, вам может понадобиться отделить логику для расчета, чтобы использовать ее повторно.

Затем вы также можете извлечь направление движения в самодостаточную функцию, и ваш handleDirection станет очень простым - вы рассчитываете направление, в котором хотите идти, на основе src и 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);

Ответ 7

У этого есть только одно условие, и я считаю, что оно читается более интуитивно, чем другие ответы:

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

Ответ 8

Вы хотите увеличить трекер, если один из src== left или inverse имеет значение true, но не другой, и уменьшить его в противном случае, что и делает оператор "XOR" ^:

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

Вы можете уменьшить это, используя троичное выражение:

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

Или, если вы хотите избежать каких-либо условных выражений с неявными приведениями и "умной" арифметикой:

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

Ответ 9

Вам не нужно, if предложение вообще. Та же самая операция может быть выполнена путем вычисления положительного или отрицательного приращения в зависимости от src и обратного с помощью только троичного оператора.

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

Btw. Для эффективности я бы рекомендовал напрямую использовать числовые приращения/убывания вместо строк, которые требуют дополнительной обработки для декодирования. Вы можете использовать константы для достижения той же читабельности:

Также обратное может быть оптимизировано как числовое значение, переключающееся между 1 (не инвертировано) и -1 (инвертировано).

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

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

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

... даже если ключевые слова "вправо" и "лево" происходят из своего рода текстового ввода, вы можете просто перевести их из словаря:

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

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

Ответ 10

Вы можете использовать синтаксис короткого замыкания или троичные операторы

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

Ответ 11

Я не люблю остальных и стараюсь избегать гнездования, если это возможно. Я думаю, что это передает идею inverse более естественным образом:

function handleDirection(src) 
{
    let change = 1;

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

    if (inverse)
        change = -change;

    tracker += change;
}

Ответ 12

Не самое короткое, но, надеюсь, ясно:

const LEFT = 'left'
const RIGHT = 'right'


function handleMovement(src) {
    tracker += movementIncrement(src, inverse)
}

function movementIncrement(direction, inverse) {
    if (inverse) {
        direction = inverseDirection(direction)
    }
    return LEFT ? -1 : +1
} 

function inverseDirection(direction) {
    return direction === LEFT ? RIGHT : LEFT
}

Ответ 13

Я знаю, что это не является прямым решением вопроса с прямым "упрощением", но я хотел бы предоставить вам ответ, который решает несколько вопросов качества кода, а также делает код более читабельным.

О побочных эффектах

Прежде всего эта функция мутирует внешние значения. Это вводит проблему побочных эффектов:

  • Функция изменяет внешнее состояние, которое может не обрабатываться во внешней среде, что может привести к неопределенному поведению.
  • Сама функция затем привязывается к внешнему состоянию, что затрудняет изменение и рефакторинг кода.

Также гораздо сложнее протестировать такую функцию, поскольку сначала нужно "создать среду состояний", чтобы запустить тест.

Первой простой настройкой было бы заставить все внешние значения принимать по параметру и просто вернуть значение 1 или -1, которое назначено какому-либо (в вашем случае tracker).

Эксклюзивно или условно со строками

Во-вторых, использование if/else для значений String с исключительным значением или может привести к неопределенному состоянию, где src может быть чем-то иным, чем 'right' но функция ведет себя так, как если бы она была 'right'. Вместо этого следует выбросить исключение. Использование переключателя является хорошей помощью здесь.

Применяя эти точки к функции

Если учесть вышеприведенные пункты, общая функция будет выглядеть следующим образом:

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

и вы можете легко проверить эту функцию:

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

Теперь функция четко отделена от tracker (подумайте о своем ценном времени при рефакторинге), но, кроме того, совершенно ясно, что делает функция.

Заметка

Подводя итог, я хотел подчеркнуть, что речь идет не всегда о написании самого простого кода с наименьшим количеством строк, но кода, который понятен для чтения/понимания и сопровождения. Это не так коротко, как многие из предоставленных решений, но каждый должен немедленно понять, что он делает.

Ответ 14

Прямо сейчас вы сравниваете строки, которые я бы не советовал. Например, если вы используете "Left" вместо "left", первый оператор if потерпит неудачу. Возможно, здесь может пригодиться логическое значение, поскольку вы можете гарантировать, что оно имеет только два состояния.

Операторы if внутри могут быть сжаты с помощью условных операторов.

Возможно, что-то вроде этого - то, что вы ищете:

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

Смотрите: https://jsfiddle.net/9zr4f3nv/

Ответ 15

Вы можете использовать двухмерную структуру данных типа массива из js и сохранять желаемые результаты по индексу sec и обратно. Или JSON.

Ответ 16

Надеюсь, поможет.

(src=== 'left')?((inverse)?tracker--:tracker++):((tracker)?tracker++:tracker--)