Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Оператор instanceof». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**`instanceof` перевіряє, чи присутній `Constructor.prototype` у ланцюжку прототипів об'єкта, тобто чи є об'єкт екземпляром певного класу або функції-конструктора.** Оператор повертає `true` або `false`, враховує все дерево спадкування (`Dog` -> `Animal` -> `Object`) і працює тільки з об'єктами: для примітивів на кшталт `123` чи `'hello'` він завжди дає `false`. ```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 ``` **Ключове:** `instanceof` це перевірка ланцюжка прототипів, а не типу значення, тому для масивів з іншого контексту (iframe) надійніший `Array.isArray()`.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Оператор `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`.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.