Оптимизация кода js, Задача подсчет каллорий и цены гамбургера

https://codepen.io/Alfa_main/pen/gJyQeN
Здравствуйте хочу попросить у вас помощи) Есть задача: Дано колличество каллорий маленького и большого гамбургера + добавки к ним, при выборе одного из гамбургеров и добавки к нему подсчитывается цена и калории обоих) Я сделал задание в лоб(совсем нехорошим способом) , каким еще способом можно решить данную задачу, более профессионально) Ссылка на codepen выше, заранее благодарен за помощь)

Способ нехороший потому что код сложно расширять. В код как-бы зашито знание о том какие бывают топпинги и какие бургеры. Обычно стратегия такая чтобы описать с помощью структур данных (массивов и объектов), и описать код в общем виде. Трюк которого я не вижу в коде, но который поможет написать код в общем виде, состоит в том чтобы использовать переменную с именем свойства объекта для доступа к значению свойства. Пример механики

const propName = 'userName'
const obj = {
    userName: 'dima',
    gender: 'male'
}
console.log(obj[propName]) // 'dima'

Далее по коду. Примерно такие структуры данных описывают достаточно хорошо ситуацию:

const burgers = {
	small: {
		price: 1,
		ccal: 10
	},
	large: {
		price: 2,
		ccal: 15
	}
}
const toppings = {
	salad: {
		price: 1,
		calories: 10
	},
	cheese: {
		price: 2,
		calories: 50
	},
	ham: {
		price: 5,
		calories: 40
	}
]

Далее нужно в html/js описать код так чтобы можно было получить при клике, строки small или large записывались в переменную burgerType.
Описать код, чтобы получить массив топпингов в виде ['cheese', 'ham'] в переменную selectedToppings

Тогда вычисление итоговых значений будет иметь достаточно общий вид:

const burgerPrice = burgers[burgerType].price
let toppingsPrice = 0
for (let i = 0; i < selectedToppings.length; i += 1) {
	const selectedToppingName = selectedToppings[i]
	toppingsPrice = toppingsPrice + toppings[selectedToppingName].price
}
const totalPrice = burgerPrice + toppingsPrice
1 лайк

Хороший способ но немного непонятно как это реализовать, я новичок и пока что не пойму как внедрить данный способ)

Ну смотри, давай попробуем начать отбрасывать лишнее:
у тебя есть объект burgers и объект stuffing, которые, по сути, описывают одно и то же: какой-то продукт, его цену, и калорийность. Но при этом структура данных у них вообще разная. И все поля называются по-разному:

// stuffing
	cheese:{
        priceCheese : 4,
        ccalCheese : 25,
	},
	salad:{
        priceSalad : 5,
        ccalSalad : 5,
	},
// burgers:
	price:{
        priceSmallGamburger : 17, 
	    priceBigGamburger : 25,
	},
    ccal:{
    	ccalSmallGamburger : 250,
    	ccalBigGamburger : 350,
    },

как эти структуры можно упростить и сделать более одинаковыми?

1 лайк

https://codepen.io/Alfa_main/pen/gNYvyg вот пробую но всеравно до конца не понятно как значение попадет в функцию

В самом начале onclick функции ты объявляешь пачку переменных (burgerType и прочие). Посмотри внимательно, что в них попадает, и как ты потом их используешь.

1 лайк

Ну вначале я объявляю константу инпутов бургеров, потом добавок к ним для того, чтобы считать выбранный инпут и применить к нему функцию, но тут нет checked у меня нигде, где то портачу и не могу найти пока что где) price is not defined, догадываюсь что это связанно с неправильным указанием DOM, не туда засовываю радиоинпуты) Возможно в selectedToppings и burgerType нужно добавить названия ключей в виде массива, но как тогда возможно считать значение инпута который отметил пользователь

Ну ок, смотри,

let burgerType = document.querySelectorAll('.radio__gamburger');
const burgerPrice = burgers[burgerType].price;

какой тип данных у burgerType?
А какой должен быть, чтобы burgers[burgerType] корректно отработал?

1 лайк

Думаю тип object https://codepen.io/Alfa_main/pen/jjOzGK типо этого но ошибка не уходит, массив попадает в переменную, и одно из его значений должно применяться к burgerPrice, но не попадает

Хорошо, давай смотреть:

    const burgers = {
	   small:{
           price : 17, 
	       ccal : 250,
	    },
        large:{
    	   price : 25,
    	   ccal : 350,
        }
	};
const burgerType = ['small','large'];
const burgerPrice = burgers[burgerType].price;

Ты передаешь в burgers ключом весь массив burgerType. Пытаясь достать из объекта значение, он превращает его в строку (потому что ключи объектов всегда - строки) 'small, large'. Потому что если ты вызовешь burgerType.toString(), то как раз эту строку и получишь.

В результате объект burgers, в котором два ключа small и large, пытается найти данные с ключом 'small, large', которых там нет. Поэтому burgers[burgerType] превращается в undefined и вот это выражение

const burgerPrice = burgers[burgerType].price;

превращается в undefined.price и падает с ошибкой Cannot read property 'price' of undefined.

2 лайка

То же самое и в прошлом примере:

let burgerType = document.querySelectorAll('.radio__gamburger');
const burgerPrice = burgers[burgerType].price;

burgerType.toString() получит на выходе какой-нибудь [object Nodelist], а такого ключа в объекте burgerPrice нет.
Да, ты выгреб два ДОМ-элемента .radio_gamburger, но ты не можешь пихать их напрямую в объект burgerPrice.
Тебе нужно:

  1. Выбрать из двух найденных ДОМ-элементов один, тот, который пользователь чекнул.
  2. Каким-то образом проассоциировать этот дом-элемент со строкой (small или large, потому что именно такие ключи есть в объекте burgers), которую ты потом передашь в объект burgers.
2 лайка