Какъв е всъщност?
Проблем
Само някои могат да се зареждат
Фирмата има автопарк от обикновени и електрически коли. Всяка вечер електрическите трябва да се заредят. ElectricCar наследява Car и добавя charge(), затова всички са в един масив:
const fleet = [ new Car("Шкода"), new ElectricCar("Тесла", 35), new Car("Дачия"), new ElectricCar("Нисан", 60),];for (const c of fleet) { c.charge();}Програмата тръгва и спира още на първата кола, „Шкода“: TypeError: c.charge is not a function. До електрическите не стига.
Обикновената кола наистина не може да се зареди. Трябва да питаш всяка кола: „ти електрическа ли си?“
Идеята
Питай обекта какъв е
for (const c of fleet) { if (c instanceof ElectricCar) { c.charge(); console.log(`${c.brand}: заредена до ${c.battery}%`); }}Тесла: заредена до 100%Нисан: заредена до 100%c instanceof ElectricCar пита обекта, към който сочи c: „ти ElectricCar ли си?“ и дава true или false. Това се казва проверка на типа.
Нова променлива не трябва. В JavaScript променливите нямат тип, затова няма какво да се превръща: щом проверката е вярна, c сочи електрическа кола и c.charge() работи. Колите остават същите.
for (const c of fleet) { if (c instanceof ElectricCar) { c.charge(); console.log(`${c.brand}: заредена до ${c.battery}%`); }}Стъпка по стъпка, с думи
- fleet е масив: 2 обикновени и 2 електрически коли.
- c сочи Шкода: instanceof дава „не“. Тялото на if се прескача.
- c сочи Тесла: instanceof дава „да“. Нова променлива не трябва: c.charge() зарежда същата кола.
- c сочи Дачия: instanceof дава „не“. Тялото на if се прескача.
- c сочи Нисан: instanceof дава „да“. Нова променлива не трябва: c.charge() зарежда същата кола.
- Колите не се променят. Проверката само пита обекта какъв е.
Пробвай
Кола ли е?
Какво ще отпечата програмата?
const c = new ElectricCar("Тесла", 35);const d = new Car("Шкода");console.log(c instanceof Car);console.log(c instanceof ElectricCar);console.log(d instanceof ElectricCar);Електрическата кола е и кола, затова първата проверка е вярна. Проверката не пита „точно Car ли е?“, а „може ли обектът да се ползва като Car?“. Обикновената кола d не е електрическа, затова последната проверка е грешна.
Идеята
Другите записи, които ще срещнеш
Освен instanceof ще срещнеш още няколко начина да питаш обекта:
const c = fleet[1];console.log(c.constructor.name);console.log(c.constructor === Car);console.log(c instanceof Car);console.log(typeof c.charge === "function", typeof fleet[0].charge === "function");console.log(typeof 42, typeof "Тесла", typeof true, typeof c);ElectricCarfalsetruetrue falsenumber string boolean objectc.constructorе класът, от който е създаден обектът, аc.constructor.nameе името му.c.constructor === Carпита „точноCarли е?“ и за електрическата кола еfalse, аc instanceof Carеtrue. Почти винаги искашinstanceof: тя приема и наследниците.typeof c.charge === "function"не пита за класа, а само дали обектът има такъв метод. Това е проверката за договор от урока „Интерфейси“: всеки обект сcharge()минава.typeofдава вида на стойността като текст:"number","string","boolean","function". За всеки обект е"object", затова класа не казва. За класа еinstanceof.
По-точно, за любопитните
- Проверката е винаги грешна за
null:null instanceof Carеfalse. Затова след успешенinstanceofникога нямашnull. - С
instanceofне можеш да питаш за договор: договорът е само имена на методи и няма клас, с който да сравниш. За него еtypeof a.swim === "function".
Пробвай
Намери грешката
Програмата брои обикновените и електрическите коли. В автопарка има две от всеки вид, а тя печата:
Обикновени: 4, електрически: 0На кой ред е грешката?
Избери реда с грешката.
Всяка електрическа кола е и Car, затова първата проверка е вярна за всички четири коли. До втората програмата не стига никога. Проверявай първо по-конкретния тип: ако е ElectricCar, брой електрическа, иначе обикновена.
Идеята
Проверка или метод?
Искаш да отпечаташ с какво се движи всяка кола. С проверка на типа става:
for (const c of fleet) { if (c instanceof ElectricCar) { console.log(`${c.brand}: ток`); } else { console.log(`${c.brand}: бензин`); }}Но това е заплатата с if по роля от урока за полиморфизма. Всяка кола има енергия, само че различна. Това е работа за метод в Car, презаписан в ElectricCar:
// в Carenergy() { return "бензин";}
// в ElectricCarenergy() { return "ток";}for (const c of fleet) { console.log(`${c.brand}: ${c.energy()}`);}Шкода: бензинТесла: токДачия: бензинНисан: токУтре идва хибридна кола. С метода пишеш нов клас. С проверките търсиш всеки if в програмата.
Правилото:
- Всеки обект го прави, но по свой начин: метод в родителя и презаписване.
- Само някои обекти го могат (зареждане, педали): проверка на типа.
Пробвай
Кое липсва?
for (const c of fleet) {
if (c ElectricCar) {
c.charge();
}
}instanceof: проверява дали c сочи ElectricCar. Ако да, c.charge() работи.Накратко
Четирите стълба на ООП
С този урок модулите „Класове и обекти“ и „Наследяване и полиморфизъм“ са минати. Обектно-ориентираното програмиране стои на четири идеи. Вече ползваш всичките:
- Капсулация. Данните на обекта са скрити, а отвън се стига до тях само през методи, които пазят правилата.
Accountдържи баланса #скрит и дава самоdeposit()иwithdraw(). Капсулация - Наследяване. Общото е на едно място, в родителя, а наследникът добавя своето.
ManagerеEmployeeс бонус. Наследяване - Полиморфизъм. Едно извикване, различно поведение според обекта.
e.monthlyPay()в един цикъл смята заплатата на служител, мениджър и стажант. Полиморфизъм - Абстракция. Казваш какво трябва да може обектът, а как решава всеки клас. Абстрактният
Shapeобещава лице, договорът за плащане обещава сума за плащане. Абстрактни класове, Интерфейси
Упражнение
Какъв е всъщност?
Реши задачите в редактора си.
1. Паркинг. Масив с обикновени и семейни коли (FamilyCar наследява SimpleCar). За всяка отпечатай какъв е типът ѝ. Внимавай с реда на проверките.
Това е SimpleCarТова е FamilyCarТова е SimpleCar2. Танци. Масив с обикновени и брейк движения. За брейк движенията отпечатай и сложността. Тя е само в BreakDanceMove, затова я питай след проверката.
moonwalk: DanceMovewindmill: BreakDanceMove, сложност 8салса: DanceMove3. Автопарк. Вземи Car и ElectricCar от упражнението в урока „Наследяване“. В масив сложи „Шкода“ с 40 л, „Тесла“ с ефективност 5, „Дачия“ с 5 л и „Нисан“ с ефективност 4. Всяка да измине 100 км: електрическите с driveElectric, останалите с drive. После отпечатай километрите и горивото или батерията.
Шкода: 100 км, гориво 30 лТесла: 100 км, батерия 80%Горивото не стига за 100 кмДачия: 0 км, гориво 5 лНисан: 100 км, батерия 75%4. Зоопарк. Абстрактен клас Animal със sound(), наследници Cat, Dog и Fish. Само Fish има и swim(): изпълнява договора „може да плува“. В цикъл през животните извикай звука на всяко, а на тези, които могат да плуват, и swim(). Договорът няма клас, затова проверката е с typeof.
Мяу, мяу!Бау, бау!Рибата мълчи.Рибата плува.Още задачи
- Педали. В упражнението от урока „Абстрактни класове“
garage[0].pedal()спираше програмата, защото там няма велосипед. Поправи го с проверка на типа: в цикъла през превозните средства всяко потегля, а само велосипедът и върти педали. - Плащания по вид. От урока „Интерфейси“: в масива payments има служители и фактури. Отпечатай отделно сумата за заплати и сумата за фактури. За Иван, Мария и двете фактури: 5500 € заплати и 2140 € фактури.
Тест