Клас розширює об’єкт?
Як ми знаємо, всі об’єкти зазвичай успадковуються від Object.prototype
й отримують доступ до «загальних» методів об’єкта, наприклад hasOwnProperty
тощо.
Наприклад:
class Rabbit {
constructor(name) {
this.name = name;
}
}
let rabbit = new Rabbit("Rab");
// метод hasOwnProperty від Object.prototype
alert( rabbit.hasOwnProperty('name') ); // true
Але що як ми пропишемо явно "class Rabbit extends Object"
– тоді результат буде відрізнятися від звичайного "class Rabbit"
?
Яка різниця?
Ось приклад такого коду (він не працює – чому? виправте його):
class Rabbit extends Object {
constructor(name) {
this.name = name;
}
}
let rabbit = new Rabbit("Rab");
alert( rabbit.hasOwnProperty('name') ); // Error
Спочатку подивімося, чому останній код не працює.
Причина стає очевидною, якщо ми спробуємо його запустити. Конструктор класу, що успадковується, повинен викликати super()
. Інакше "this"
буде не визначене.
Виправлення:
class Rabbit extends Object {
constructor(name) {
super(); // потрібно викликати батьківський конструктор під час успадкування
this.name = name;
}
}
let rabbit = new Rabbit("Rab");
alert( rabbit.hasOwnProperty('name') ); // true
Але це ще не все.
Навіть після виправлення все ще існує важлива різниця між "class Rabbit extends Object"
та class Rabbit
.
Як ми знаємо, синтаксис “extends” встановлює два прототипи:
- Між
"prototype"
функцій-конструкторів (для методів). - Між самими функціями-конструкторами (для статичних методів).
У нашому випадку для class Rabbit extends Object
це означає:
class Rabbit extends Object {}
alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true
alert( Rabbit.__proto__ === Object ); // (2) true
Отже, Rabbit
тепер надає доступ до статичних методів Object
через Rabbit
, наприклад:
class Rabbit extends Object {}
// зазвичай ми викликаємо Object.getOwnPropertyNames
alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // a,b
Але якщо у нас немає extends Object
, тоді для Rabbit.__proto__
не встановлено значення Object
.
Приклад:
class Rabbit {}
alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true
alert( Rabbit.__proto__ === Object ); // (2) false (!)
alert( Rabbit.__proto__ === Function.prototype ); // як у будь-якої функції за замовчуванням
// помилка, такої функції в Rabbit немає
alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // Error
Тому Rabbit
не надає доступу до статичних методів Object
у цьому випадку.
До речі, Function.prototype
має “загальні” методи функції, такі як call
, bind
тощо. Вони в кінцевому підсумку доступні в обох випадках, тому що для вбудованого конструктора Object
, Object.__proto__ === Function.prototype
.
Приклад на картинці:
Коротко кажучи, є дві відмінності:
class Rabbit | class Rabbit extends Object |
---|---|
– | необхідно викликати super() в конструкторі |
Rabbit.__proto__ === Function.prototype |
Rabbit.__proto__ === Object |