Skip to main content

Оператор instanceof

Оператор instanceof у JavaScript перевіряє, чи є об'єкт екземпляром (instance) певного класу або функції-конструктора. Технічно він з'ясовує, чи присутній Constructor.prototype у ланцюжку прототипів цього об'єкта.

Теорія

TL;DR

  • Синтаксис: object instanceof Constructor, результат завжди true або false.
  • Оператор іде вгору по ланцюжку прототипів об'єкта і шукає в ньому Constructor.prototype.
  • Враховує спадкування: rex instanceof Animal дасть true навіть якщо rex створено з класу Dog extends Animal.
  • Майже все є нащадком Object, тому obj instanceof Object зазвичай true.
  • З примітивами не працює: 123 instanceof Number це false.
  • У різних контекстах (iframe, worker) свої конструктори, тому для масивів надійніший Array.isArray().

Швидкий приклад

javascript
class User {} const user = new User(); console.log(user instanceof User); // true console.log(user instanceof Object); // true, бо всі об'єкти успадковують Object

Тут user є екземпляром User і водночас екземпляром Object, оскільки User успадковує Object.

Як це працює під капотом

instanceof не дивиться на «тип» значення, він обходить ланцюжок прототипів:

  1. бере object.__proto__ (тобто Object.getPrototypeOf(object));
  2. порівнює його з Constructor.prototype;
  3. якщо збігу немає, піднімається на рівень вище: object.__proto__.__proto__ і так далі;
  4. якщо десь у ланцюжку знайдено збіг, повертає true, якщо ланцюжок закінчився на null, повертає false.
javascript
function Animal() {} const dog = new Animal(); // Перевірка: console.log(dog instanceof Animal); // true // Те саме вручну: console.log(Object.getPrototypeOf(dog) === Animal.prototype); // true

Клас може перевизначити цю поведінку через well-known символ Symbol.hasInstance: якщо він є у конструктора, instanceof викличе саме його замість стандартного обходу прототипів.

Спадкування і вбудовані типи

Оператор піднімається по всьому дереву спадкування, а не лише на один рівень:

javascript
class Animal {} class Dog extends Animal {} const rex = new Dog(); console.log(rex instanceof Dog); // true console.log(rex instanceof Animal); // true console.log(rex instanceof Object); // true console.log(rex instanceof Array); // false

Ланцюжок тут такий: Dog -> Animal -> Object.

Так само це працює зі звичайними функціями-конструкторами:

javascript
function Car() {} function Bike() {} const roadster = new Car(); console.log(roadster instanceof Car); // true console.log(roadster instanceof Bike); // false

І з вбудованими типами, наприклад з масивами:

javascript
const arr = [1, 2, 3]; console.log(arr instanceof Array); // true console.log(arr instanceof Object); // true

Усі масиви це об'єкти, тому arr instanceof Object теж true.

Примітиви та об'єкти-обгортки

З примітивами instanceof не працює взагалі:

javascript
console.log(123 instanceof Number); // false console.log('hello' instanceof String); // false

Причина проста: 123 і 'hello' це примітиви, а не об'єкти, у них немає власного ланцюжка прототипів, який можна було б обійти.

А от об'єкти-обгортки перевіряються нормально:

javascript
const n = new Number(123); console.log(n instanceof Number); // true const s = new String('hi'); console.log(s instanceof String); // true

У реальному коді обгортки new Number та new String практично не використовують, краще працювати з примітивами.

Коли instanceof підводить: інші контексти

Якщо об'єкт прийшов з іншого контексту (iframe, окреме вікно, worker), перевірка може несподівано дати false, бо в того контексту свій власний конструктор Array зі своїм prototype:

javascript
iframe.contentWindow.Array !== window.Array;

Тобто значення справді є масивом, але value instanceof Array поверне false. Для такого випадку існує окрема перевірка, яка працює між контекстами:

javascript
Array.isArray(value);

Підсумкова таблиця

ХарактеристикаЗначення
Що перевіряєЧи є Constructor.prototype у ланцюжку прототипів об'єкта
Що повертаєtrue / false
З чим працюєЗ об'єктами, не з примітивами
За чим порівнюєЗа Constructor.prototype
Чи враховує спадкуванняТак
Чи підходить для масивів, класів, функційТак

Приклад для закріплення:

javascript
class Person {} class Developer extends Person {} const tim = new Developer(); console.log(tim instanceof Developer); // true console.log(tim instanceof Person); // true console.log(tim instanceof Object); // true console.log(tim instanceof Array); // false

Типові помилки

  • Очікувати true для примітивів. 'hello' instanceof String це false; щоб перевірити примітив, потрібен typeof.
  • Плутати instanceof з typeof. typeof дивиться на тип значення, instanceof на ланцюжок прототипів; для звичайного об'єкта typeof завжди дасть 'object'.
  • Перевіряти масив через instanceof Array у коді, що приймає дані з iframe або worker. Правильний інструмент тут Array.isArray().
  • Забувати, що майже все є екземпляром Object. Перевірка value instanceof Object майже нічого не доводить, крім того, що це не примітив.
  • Використовувати instanceof на null або undefined. Результат завжди false, і жодної помилки не буде, тому баг легко пропустити.
  • Змінювати prototype конструктора після створення об'єктів. Старі екземпляри посилаються на попередній прототип, тому instanceof для них стане false.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.