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