Към съдържанието
wannacode

Какъв е всъщност?

Проблем

Само някои могат да се зареждат

Фирмата има автопарк от обикновени и електрически коли. Всяка вечер електрическите трябва да се заредят. 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}%`);
}
}
Стъпка по стъпка, с думи
  1. fleet е масив: 2 обикновени и 2 електрически коли.
  2. c сочи Шкода: instanceof дава „не“. Тялото на if се прескача.
  3. c сочи Тесла: instanceof дава „да“. Нова променлива не трябва: c.charge() зарежда същата кола.
  4. c сочи Дачия: instanceof дава „не“. Тялото на if се прескача.
  5. c сочи Нисан: instanceof дава „да“. Нова променлива не трябва: c.charge() зарежда същата кола.
  6. Колите не се променят. Проверката само пита обекта какъв е.

Пробвай

Кола ли е?

Какво ще отпечата програмата?

const c = new ElectricCar("Тесла", 35);
const d = new Car("Шкода");
console.log(c instanceof Car);
console.log(c instanceof ElectricCar);
console.log(d instanceof ElectricCar);
Отговор

Идеята

Другите записи, които ще срещнеш

Освен 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);
Изход
ElectricCar
false
true
true false
number string boolean object
  • c.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

На кой ред е грешката?

Избери реда с грешката.

Идеята

Проверка или метод?

Искаш да отпечаташ с какво се движи всяка кола. С проверка на типа става:

for (const c of fleet) {
if (c instanceof ElectricCar) {
console.log(`${c.brand}: ток`);
} else {
console.log(`${c.brand}: бензин`);
}
}

Но това е заплатата с if по роля от урока за полиморфизма. Всяка кола има енергия, само че различна. Това е работа за метод в Car, презаписан в ElectricCar:

// в Car
energy() {
return "бензин";
}
// в ElectricCar
energy() {
return "ток";
}
for (const c of fleet) {
console.log(`${c.brand}: ${c.energy()}`);
}
Изход
Шкода: бензин
Тесла: ток
Дачия: бензин
Нисан: ток

Утре идва хибридна кола. С метода пишеш нов клас. С проверките търсиш всеки if в програмата.

Правилото:

  • Всеки обект го прави, но по свой начин: метод в родителя и презаписване.
  • Само някои обекти го могат (зареждане, педали): проверка на типа.

Пробвай

Кое липсва?

for (const c of fleet) {
  if (c  ElectricCar) {
    c.charge();
  }
}

Накратко

Четирите стълба на ООП

С този урок модулите „Класове и обекти“ и „Наследяване и полиморфизъм“ са минати. Обектно-ориентираното програмиране стои на четири идеи. Вече ползваш всичките:

  • Капсулация. Данните на обекта са скрити, а отвън се стига до тях само през методи, които пазят правилата. Account държи баланса #скрит и дава само deposit() и withdraw(). Капсулация
  • Наследяване. Общото е на едно място, в родителя, а наследникът добавя своето. Manager е Employee с бонус. Наследяване
  • Полиморфизъм. Едно извикване, различно поведение според обекта. e.monthlyPay() в един цикъл смята заплатата на служител, мениджър и стажант. Полиморфизъм
  • Абстракция. Казваш какво трябва да може обектът, а как решава всеки клас. Абстрактният Shape обещава лице, договорът за плащане обещава сума за плащане. Абстрактни класове, Интерфейси

Упражнение

Какъв е всъщност?

Реши задачите в редактора си.

1. Паркинг. Масив с обикновени и семейни коли (FamilyCar наследява SimpleCar). За всяка отпечатай какъв е типът ѝ. Внимавай с реда на проверките.

Изход
Това е SimpleCar
Това е FamilyCar
Това е SimpleCar

2. Танци. Масив с обикновени и брейк движения. За брейк движенията отпечатай и сложността. Тя е само в BreakDanceMove, затова я питай след проверката.

Изход
moonwalk: DanceMove
windmill: BreakDanceMove, сложност 8
салса: DanceMove

3. Автопарк. Вземи 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 € фактури.

Тест

Провери се

1. c instanceof ElectricCar е вярно. Как зареждаш колата?
2. c сочи ElectricCar. Колко е c instanceof Car?
3. Проверяваш дали колата е Car или ElectricCar. В какъв ред?
4. В програмата има много if-ове „ако е ElectricCar, прави едно, иначе друго“. Какво подсказва това?
5. c сочи обикновена кола. Какво става при c.charge(), без проверка преди това?

Създаден от Иво Гергов като част от кампанията на Evo Tech за достъпно обучение по програмиране ·