Свой тип
Проблем
Цените се разбъркаха
Пишеш количката на онлайн магазин. Всеки продукт има име и цена, затова ги пазиш в два масива: на индекс 0 са името и цената на първия продукт, на индекс 1 на втория.
Искаш най-скъпото най-отпред и разменяш цените:
const names = ["Хляб", "Мляко", "Кафе"];const prices = [1.20, 2.10, 7.50];
// Най-скъпото отпред: разменяме първата и третата цена.const temp = prices[0];prices[0] = prices[2];prices[2] = temp;
for (let i = 0; i < names.length; i++) { console.log(`${names[i]}: ${prices[i]} €`);}Хляб: 7.5 €Мляко: 2.1 €Кафе: 1.2 €Хлябът вече струва 7,50 €. Цените са разменени, а имената не са. Двата масива трябва да се пипат винаги заедно, но нищо не те задължава. Добавиш ли трети масив с бройките, ще трябва да помниш три.
Идеята
Един продукт, едно място
Името и цената не са отделни неща. Те са части от един продукт. Искаме тип „продукт“, както има тип number за число и string за текст.
Такъв тип си правиш сам. Той се казва клас:
class Product { name; price; quantity;}Променливите в класа са неговите полета. Всеки продукт ще има свое име, своя цена и своя бройка.
Класът е само описание: „всеки продукт има име, цена и бройка“. Продукт още няма.
Името на класа започва с главна буква (Product), а имената на полетата с малка (name, price). Така веднага се вижда кое е тип и кое е стойност.
Идеята
new: от описанието към продукт
Конкретен продукт по класа се създава с new. Той се казва обект. До полетата му стигаш с точка:
class Product { name; price; quantity;}
const bread = new Product();bread.name = "Хляб";bread.price = 1.20;bread.quantity = 2;
const coffee = new Product();coffee.name = "Кафе";coffee.price = 7.50;coffee.quantity = 1;
console.log(`${bread.name}: ${bread.price * bread.quantity} €`);console.log(`${coffee.name}: ${coffee.price * coffee.quantity} €`);Хляб: 2.4 €Кафе: 7.5 €- Класът стои над кода, който го ползва. Във файла може да има няколко класа.
new Product()създава нов обект. Всеки обект има свои полета: хлябът и кафето не си пречат.bread.priceе „цената на хляба“. Чете се и се записва като обикновена променлива.const breadзначи, чеbreadвинаги сочи същия обект. Полетата на обекта пак може да се сменят.
Сега името и цената на продукта са на едно място. Разместиш ли продукта, те вървят заедно.
Пробвай
Нищо не е попълнено
Ако създадеш продукт и не попълниш нищо, какво има в полетата?
Какво ще отпечата програмата?
const item = new Product();console.log(item.name);console.log(item.price);console.log(item.quantity);Поле, обявено без стойност (name;), е undefined: „още няма стойност“. Не е 0 и не е празен текст. Същото е и с променлива, обявена без стойност: след let total; в total има undefined.
Пробвай
Кое липсва?
Какво трябва да пише на празното място, за да има нов продукт?
const milk = Product();
milk.name = "Мляко";
milk.price = 2.10;new: само той създава обект. Без него програмата спира с TypeError: Class constructor Product cannot be invoked without 'new'.Виж го
Променливата сочи към обекта
Искаш промоция на кафето и правиш „копие“, за да му смениш цената:
const coffee = new Product();coffee.price = 10;const sale = coffee;sale.price = 8;console.log(coffee.price); // 8Стъпка по стъпка, с думи
- new прави обекта: полетата му още са undefined. В coffee отива стрелка към него.
- По стрелката от coffee: цената на обекта става 10.
- sale = coffee копира стрелката, не обекта. Две стрелки, един обект.
- По стрелката от sale: цената в същия обект става 8.
- coffee сочи същия обект, затова печата 8.
Цената на кафето също стана 8. Причината е, че променливата coffee не е самият обект. Обектът стои отделно в паметта, а coffee пази къде е той: стрелка към обекта. Такава променлива се казва референция.
sale = coffee копира стрелката, а не обекта. Сега две стрелки сочат един обект, затова промяната през sale се вижда и през coffee.
Същото видя в урока за масивите: sale = prices даде второ име на същия масив. Масивът също е обект.
Идеята
Отстъпката вече работи
В модул „Функции“ отстъпката не се получи: функцията получи цената, смени своя параметър и промяната изчезна. С обект е друго:
function discount(p, percent) { p.price = p.price * (100 - percent) / 100;}
const coffee = new Product();coffee.price = 10;discount(coffee, 10);console.log(coffee.price);9Параметърът пак е копие, но копие на стрелката. Тя сочи същия обект, затова промяната на p.price остава и след функцията.
По-точно, за любопитните
Ако функцията сложи в параметъра нов обект, тя мести само своето копие на стрелката. Обектът отвън не се променя:
function reset(p) { p = new Product(); p.price = 0;}
const coffee = new Product();coffee.price = 10;reset(coffee);console.log(coffee.price);10Идеята
null: стрелка за никъде
Променлива може да не сочи към никакъв обект. Тогава в нея е null: „нищо“. Ако опиташ да прочетеш поле през нея, няма обект, от който да го прочетеш:
const gift = null;console.log(gift.name);Програмата тръгва, но спира с грешка, когато стигне до реда:
TypeError: Cannot read properties of null (reading 'name')Това е най-честата грешка с обекти. Какво е „exception“ и как се хваща, ще видим в модул „Грешки и изключения“.
Масивът също пази стрелки, а не самите продукти. new Array(3).fill(null) прави три места, които още не сочат към продукт. Всяко е null, докато не сложиш там new Product():
const cart = new Array(3).fill(null);console.log(cart[0] === null);cart[0] = new Product();cart[0].name = "Хляб";console.log(cart[0].name);trueХлябПробвай
Намери грешката
Програмата трябва да отпечата „Хляб“ и „Мляко“. Вместо това печата „Мляко“ два пъти. На кой ред е грешката?
Избери реда с грешката.
const milk = bread; не прави нов продукт. Сега milk и bread сочат един и същ обект, и името „Мляко“ замества „Хляб“. Поправката е const milk = new Product();.
Упражнение
Твоите класове
1. Книга. Клас Book с полета за заглавие и автор. Създай две книги и ги отпечатай.
Под игото от Иван ВазовТютюн от Димитър Димов2. Кола. Клас SimpleCar с поле за скоростта. Създай кола (скоростта ѝ е 0), увеличи скоростта с 10 и я отпечатай. Дай на полето начална стойност (speed = 0;): без нея undefined + 10 дава NaN, „не е число“. В урока „Поведение“ това ще стане метод на колата.
Скорост след ускоряване: 103. Количката. Количката от първата карта, този път с масив от три обекта Product: хляб 1,20 € (2 броя), мляко 2,10 € (1 брой), кафе 7,50 € (1 брой). Отпечатай сумата за всеки ред и общата сума. Всеки продукт първо се създава с new Product(), а после влиза в масива.
Хляб x2: 2.4 €Мляко x1: 2.1 €Кафе x1: 7.5 €Общо: 12 €4. Най-скъпото отпред. Подреди същата количка по цена, от най-скъпото към най-евтиното, с метода на мехурчето от урока за масивите. Този път разменяш цели продукти, затова името и цената вървят заедно.
Кафе: 7.5 €Мляко: 2.1 €Хляб: 1.2 €Още задачи
- Ученик. Клас
Studentс име и три оценки (три полета). Създай двама ученици и отпечатай средния успех на всеки. - Една книга, две имена. Създай книга, запиши я в две променливи и смени заглавието през втората. Отпечатай заглавието през първата. Обясни с думи защо е така.
Тест