在此 js 代码片段中使用 break 语句是一种好习惯吗?

Is it good practice to use a break statement in this js code snippet?

此函数的目的是根据给定的航空公司费率 table(参数 1)和重量(参数 2)计算价格(结果)。 rates 数组中的数组行表示:[weight break, rate/kg, breakpoint].

计算示例:

注意:费率 table 的最后一行没有 bp。这就是这些 table 的提供方式。

TLDR:

我的代码工作得很好(见下文),但我对此很陌生,我想知道是否有更好的方法来编写这个小算法。我发现了递归,但我不确定如何编写递归函数。也许这可以用更简洁的方式编写?我问这个问题是为了更好地编码。谢谢!

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);

我认为有几种方法可以使它更简洁易读。这真的只是一些小事。

第一个是 JavaScript 技巧,称为 destructuring assignment。这将允许您为数组中的值指定变量名称,如下所示:

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

然后这个:arr[i][0] * arr[i][1] 变成 weightBreak * rate

另一件小事是格式化(可能只需要将其输入到本网站)。即使它看起来微不足道,正确格式化您的代码对提高可读性也有很大帮助。

最后一件事:如果我们在 arr 中的 weight <= arr[i][0]weight <= arr[i][2] 中找不到任何项目,那么看起来可以在每次迭代中调用 else 块。在这种情况下,我们返回的是基于 arr 中最后一项的值。如果我们使用早期的 return 语句而不是 break 语句,我们可以将该部分完全从循环中拉出来。

如果我们将所有这些放在一起,那么我们得到:

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

如果您希望我澄清其中任何一个,请随时提问!希望对您有所帮助,祝您编码愉快!

这是用 recursion 标记的,我认为这是一个有用的调用。使用解构和默认参数的此函数的递归版本最终变得非常简单:

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,我们可以避免对是否存在第三个条目进行任何特殊检查。此外,关于如何进行实际计算的逻辑被简化了,注意我们只需要与断点进行比较,使用 max 选择要与我们的速率相乘的值。所以如果权重小于断点,我们可以returnrate * Math .max (wb, weight)。如果不是,那么我们重复数组的剩余元素。

另外,您的标题询问了break语句的使用。我认为你的直觉是正确的;这些应该很少见。他们通常会指出经过严格重构后可能表现良好的代码。除了上面的递归技术之外,您还可以使用 const [wp, rate, bp = Infinity] = rates.find(([ , , bp]) => weight <= bp) 之类的方法来管理它。这也将避免 break 语句以及显式 for-loop.

更新

通过谨慎使用默认参数,此版本携带更多 error-correction:

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 的数组不存在,或者它为空,或者缺少某些值,它不会抛出错误。相反,在大多数情况下,它将 return 归零。它将处理任何 weight,再次使用 Infinity 捕获尚未匹配的大值。