JavaScript - Function Issue

I'm new using JavaScript and I'm trying to accomplish the follow exercise:

I have an array named bill with 3 elements [124, 48, 268]

I want to call a function which calculates the tip depending on bill amount, less than $50 (percentage = 0.2), bill amount between $50 and $ 200 (percentage = 0.15) and bill amount over $ 200 (percentage = 0.1)

I have used the following code:

    var bill = [124, 48, 268];

    var percCalculation = function(amount) {
        var percentage;
        switch(amount) {
            case (amount < 50):
                percentage = .2;
            case (amount >= 50 && amount < 200):
                percentage = .15;
            case (amount > 200):
                percentage = .1;
        }
        return percentage * amount
    }

    var tipAmount = [percCalculation(bill[0]),
    percCalculation(bill[1]),
    percCalculation(bill[2])];

    console.log(tipAmount);

However, I get the following results: (3) [NaN, NaN, NaN]

What is wrong with the code?

Upvotes: 0

Views: 42

Answers (2)

Jaromanda X
Jaromanda X

Reputation: 1

your switch statement for the first amount, 124 would look like

var percentage = undefined; // implied value of undeifned
switch(124) {
  case false: ......
  case true: ....
  case false: ....
}
return 124 * undefined; // this is Nan

Since no cases match 124, percentage never gets a value, and you get NaN as a result

So, you want to switch(true) as only one case will ever be true

You also want to break at the end of each case so the execution doesn't "fall through" to the next case

A little bonus, your function can be used as a callback to Array#map method - see bottom of snippet

var percCalculation = function(amount) {
    var percentage;
    switch(true) {
        case (amount < 50):
            percentage = .2;
            break;
        case (amount >= 50 && amount < 200):
            percentage = .15;
            break;
        case (amount > 200):
            percentage = .1;
            break;
    }
    return (percentage * amount).toFixed(2) // returns a nice dollar and cents
}

var bill = [124, 48, 268];
var tipAmount = [percCalculation(bill[0]),
percCalculation(bill[1]),
percCalculation(bill[2])];

console.log(tipAmount);

// bonus ... use map to make your code "DRY"
var tip2 = bill.map(percCalculation);
console.log(tip2);

Please note: your logic would mean that if the amount is exactly 200, you will get a NaN result ... you need to either check <= 200 in second case or >= 200 in third case (as you've done for the 50 cutoff)

a brief note about the above usage of switch ... many languages have switch but won't allow multiple case with the same value - javascript does (not sure which other languages allow it) so, just be careful if using another language

Upvotes: 1

tadman
tadman

Reputation: 211740

Remember switch cases "fall-through", as in keep executing until hitting a break, return or the end of the switch, so:

var percCalculation = function(amount) {
var percentage;
switch(amount) {
    case (amount < 50):
        percentage = .2;
        break;
    case (amount >= 50 && amount < 200):
        percentage = .15;
        break;
    case (amount > 200):
        percentage = .1;
        break;
}
return percentage * amount
}

var bill = [124, 48, 268];
var tipAmount = [percCalculation(bill[0]),
percCalculation(bill[1]),
percCalculation(bill[2])];

console.log(tipAmount);

While that fixes the fall-through problem, it exposes another more serious one and that is the case values are evaluated through matching, as in amount must match one of the fully evaluted versions of those case expressions, so this looks like:

switch(amount) {
  case true:
     // ...
  case false:
     // ...
  case false:
     // ...
}

So it must be converted to if statements:

var percCalculation = function(amount) {
var percentage;
if (amount < 50)
    percentage = .2;
if (amount >= 50 && amount < 200)
    percentage = .15;
if (amount > 200)
    percentage = .1;

return percentage * amount;
}

var bill = [124, 48, 268];
var tipAmount = [percCalculation(bill[0]),
percCalculation(bill[1]),
percCalculation(bill[2])];

console.log(tipAmount);

Note you have an error in your logic, if amount is 200 it will not match anything and crash out using an undefined value in multiplication. I prefer to use more data-driven definitions, like this:

percentageForAmount = [
  [ 200, 0.1 ],
  [ 50, 0.15 ],
  [ 0, 0.2 ]
];

Where you can look up values in that easily:

let rate = percentageForAmount.find((min, perc) => amount > min);

let percentage = rate[1];

It's also worth noting that it's generally better to define functions as functions, not as var variables. There's no reason to redefine this each time you run it as nothing changes.

In other words:

function percCalculation(amount) {
  // ...
}

Where you can call that as many times as you want with no additional overhead.

Upvotes: 1

Related Questions