назад до уроку

Клас розширює об’єкт?

важливість: 3

Як ми знаємо, всі об’єкти зазвичай успадковуються від 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” встановлює два прототипи:

  1. Між "prototype" функцій-конструкторів (для методів).
  2. Між самими функціями-конструкторами (для статичних методів).

У нашому випадку для 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