Home > Software engineering >  JavaScript Accessing literal object property
JavaScript Accessing literal object property

Time:04-20

I'm trying to make this function that tells me which guitar I can purchased based on the budged. My issue is that I created a literal object and all outputs are giving the same answer (Except condition one) because I am trying to access the properties inside.

What would be the best way to access the property that has the name of the item? Also, please correct any wrong terminology I use.

let instruments = {
  guitar1: ["Gibson SG", "$3500"],
  guitar2: ["Fender Strat", "$3000"],
  guitar3: ["Ibanez JEM Custom", "$4200"]
};

function howMuchMoney() {


  let money = prompt("What's your budget?");


  if (money < 3000) {
    alert("Broke")
  } else if (money >= 3000) {
    alert(`Buy the ${instruments.guitar1[0]}`)
  } else if (money >= 3000) {
    alert(`Buy the ${instruments.guitar2[0]}`)
  } else if (money >= 4200) {
    alert(`Buy the ${instruments.guitar3[0]}`)
  }

}
howMuchMoney()

CodePudding user response:

There are two main issues with your program:

prompt() returns a string

prompt() returns a string but you want to do comparisons on numbers so you need to convert the string to a number first using Number.parseFloat(). Otherwise you will just be checking on a lexicographic basis which could potentially give you unexpected results.

Order of else ifs

You need to arrange your else if statements in a way that every else if could actually be reached otherwise there is no point defining those other cases as only ever one can be triggered. So arrange them from most money to least money when using <=.

Just a remark: Try to use const instead of let whenever you are not changing the value which is (or should be) almost always.

const instruments = {
  guitar1: ["Gibson SG", "$3500"],
  guitar2: ["Fender Strat", "$3000"],
  guitar3: ["Ibanez JEM Custom", "$4200"],
};

while (true) {
  // we get a string here
  const moneyStr = prompt(`What's your budget?\n(Enter "exit" to end program)`);
  // end the inifinite loop if someone has entered "exit"
  if (moneyStr === "exit" || moneyStr === null) break;
  // parse the string to a float number
  const money = Number.parseFloat(moneyStr);
  // if the string cannot be parsed show error message and go to next iteration in loop meaning we ask for the input again
  if (isNaN(money)) {
    alert("Invalid input. Budget must be a number!");
    continue;
  }
  // money is now a number
  tellGuitar(money);
  break;
}

/**
 * Tell user which guitar to buy
 * @param {number} money money the user has
 */
function tellGuitar(money) {
  // broke first
  if (money < 3000) {
    alert("Broke");
    // now go from most mones to least money as otherwise the other cases will never trigger
  } else if (money >= 4200) {
    alert(`Buy the ${instruments.guitar3[0]}`);
  } else if (money >= 3500) {
    alert(`Buy the ${instruments.guitar1[0]}`);
  } else if (money >= 3000) {
    alert(`Buy the ${instruments.guitar2[0]}`);
  }
}

For reason of simplicity I have wrapped the program in an infinite loop when an invalid input is entered that cannot be converted to a number. To exit the program despite the infinite loop I have added an exit command. The program will also exit when Cancel is pressed (i.e. prompt() returns null). The actual logic to tell the user which guitar to buy was factored out into another method tellGuitar() which receives the money as a number.

CodePudding user response:

You really should be able to support the hypothetical case of if your instruments array hypothetically contained millions of instruments. That way, you won't hardcode any values. Check this solution.

<button onclick="sendPrompt()">Click me</button>

<script>
    const instruments = {
        guitar1: ['Gibson SG', '$3500'],
        guitar2: ['Fender Strat', '$3000'],
        guitar3: ['Ibanez JEM Custom', '$4200'],
        guitar4: ['Jimi Hendrix Golden Limited Edition', '$500000000']
    };

    const calculateInstrument = (instruments, money) => {
        let bestOption = {
            diff: null,
            name: null,
        };

        for (const [name, price] of Object.values(instruments)) {
            const parsed =  price.slice(1);
            const diff = money - parsed;

            if (diff === 0) return name;

            if ((bestOption.diff > diff && diff > 0) || diff > 0) bestOption = { name, diff };
        }

        return bestOption.name;
    };

    const sendPrompt = () => {
        const val = prompt("What's your budget?");

        if (!/^[0-9] $/.test(val)) return alert('Error! Only numbers!');

        const name = calculateInstrument(instruments,  val);

        if (!name) return alert('You broke.')
        alert(`You should buy ${name}`);
    };
</script>

CodePudding user response:

I made you a solution using the map() method, which allows you to go through all the keys, getting only those keys whose price matches the specified budget of variable money.

Output the result in the console.

For example:

if you specify a budget as $4000, you will get a list of all guitars of equal and lesser value.

let instruments = {
    guitar1: ["Gibson SG", "$3500"],
    guitar2: ["Fender Strat", "$3000"],
    guitar3: ["Ibanez JEM Custom", "$4200"],
};

function howMuchMoney() {
    let money = prompt("What's your budget?");

    Object.keys(instruments).map((key, index) => {
        let price = instruments[key][1].replace("$", "");

        if (price <= money) {
            console.log(instruments[key][0]);
        }
    });
}

howMuchMoney();

  • Related