Является ли хорошей практикой использование оператора break в этом фрагменте кода js? - PullRequest
3 голосов
/ 20 июня 2020

Цель этой функции - вычислить цену (результат) на основе заданной таблицы тарифов авиакомпании (параметр 1) и веса (параметр 2). Строка массива в массиве ставок означает: [весовой разрыв, ставка / кг, точка останова].

Пример расчета:

  • проверка, ниже ли данный вес разрыва веса ( wb), примените минимальную ставку, которая равна wb * rate;
  • , если нет, проверьте, не ниже ли вес контрольной точки (bp), вычислите weight * rate;
  • , если вес выше, чем bp, применить wb следующего массива, умноженное на скорость следующего массива.

Примечание: последняя строка в таблице тарифов нет bp. Вот так и представлены эти таблицы.

TL; DR:

Мой код работает нормально (см. Ниже), но я новичок в этом, и мне интересно, есть ли лучший способ написать этот маленький алгоритм. Я заметил рекурсию, но не знаю, как написать рекурсивную функцию. Может быть, это можно написать более кратко? Я задаю вопрос, чтобы научиться кодить лучше. Спасибо!

rates = [
    [ 45, 3.8, 88 ],
    [ 100, 3.35, 296 ],
    [ 300, 3.3, 492 ],
    [ 500, 3.25]
];

function calcPrice(arr, weight) {
    let price = 0;
    for (let i = 0; i < arr.length; i++) {
        if (weight <= arr[i][0]) {
            price = arr[i][0] * arr[i][1]; break;
        } else if (weight <= arr[i][2] && arr[i][2] !== undefined) {
            price = weight * arr[i][1]; break;
        } else {
            price = weight * arr[i][1];
        }
    }
    return price;
}
console.log(calcPrice(rates, 89);

Ответы [ 2 ]

2 голосов
/ 20 июня 2020

Думаю, есть несколько способов сделать это более кратким и читаемым. На самом деле это всего лишь пара мелких вещей.

Первый - это трюк JavaScript, называемый деструктурирующим присваиванием . Это позволит вам присвоить имена переменных значениям в массивах следующим образом:

const [weightBreak, rate, breakpoint] = arr[i];

Тогда это: arr[i][0] * arr[i][1] станет weightBreak * rate.

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

И последнее: похоже, что блок else может вызываться на каждой итерации, если мы не найдем никаких элементов в arr где weight <= arr[i][0] или weight <= arr[i][2]. В этом случае мы возвращаем значение, основанное на последнем элементе в arr. Если мы используем ранние операторы return вместо операторов break, мы могли бы полностью вытащить эту часть из l oop.

Если сложить все это вместе, мы получим:

function calcPrice(arr, weight) {
  for (let i = 0; i < arr.length; i++) {
    const [weightBreak, rate, breakpoint] = arr[i];

    if (weight <= weightBreak) {
      return weightBreak * rate;
    }

    if (weight <= breakpoint && breakpoint !== undefined) {
      return weight * rate;
    }
  }

  const lastItem = arr[arr.length - 1];
  return weight * lastItem[1];
}

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

0 голосов
/ 22 июня 2020

Это было помечено рекурсией , и я думаю, что это полезный вызов. Рекурсивная версия этой функции с использованием деструктуризации и параметров по умолчанию оказывается довольно простой:

const calcPrice = ([[wb, rate, bp = Infinity], ...rates], weight = 0) =>
  weight < bp 
    ? rate * Math .max (wb, weight) 
    : calcPrice (rates, weight);

const rates = [[45, 3.8, 88], [100, 3.35, 296], [300, 3.3, 492], [500, 3.25]];

const vals = [33, 47, 85, 90, 103, 296, 297, 302, 490, 497, 2001]
vals .forEach (v => console .log (`${v} : ${calcPrice(rates, v).toFixed(2)}`))

Обратите внимание, что, задав для точки останова значение по умолчанию Infinity, мы можем избежать специальной проверки существования третьей записи. Кроме того, лог c о том, как выполнять фактические вычисления, упрощен, поскольку мы должны сравнивать только с точкой останова, используя max, чтобы выбрать значение, которое будет умножаться на нашу ставку. Итак, если вес меньше точки останова, мы можем вернуть rate * Math .max (wb, weight). Если это не так, мы повторяемся для оставшихся элементов нашего массива.

Кроме того, в вашем заголовке спрашивается об использовании оператора break. Я думаю, ваш инстинкт верен; они должны быть довольно редкими. Обычно они указывают на код, который может хорошо справиться с серьезным рефакторингом. Помимо описанной выше рекурсивной техники, вы также можете управлять этим, используя что-то вроде const [wp, rate, bp = Infinity] = rates.find(([ , , bp]) => weight <= bp). Это также позволило бы избежать операторов break, а также явного for -l oop.

Update

Эта версия содержит гораздо больше исправлений ошибок за счет осторожного использования Параметры по умолчанию:

const calcPrice = (
  [[weightbreak = 0, rate = 0, breakpoint = Infinity] = [0, 0, Infinity], ...rates] = [], 
  weight = 0
) =>
  weight < breakpoint
    ? rate * Math .max (weightbreak, weight) 
    : calcPrice (rates, weight);

Он не выдаст ошибку, если массив rates не существует, или если он пуст, или если некоторые значения отсутствуют. Вместо этого в большинстве случаев он вернет ноль. И он будет обрабатывать любые weight, снова используя Infinity для захвата больших значений, которые еще не совпали.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...