instanceof та прототипи
оператор instanceof напряму пов'язаний із прототипами
і буквально перевіряє:
"Чи знаходиться
prototypeконструктора десь у ланцюжку прототипів об'єкта?"
Розберемо по кроках.
Коротко
Синтаксис:
obj instanceof ConstructorПовертає true, якщо
у ланцюжку прототипів об'єкта obj
присутній об'єкт Constructor.prototype.
Інакше повертає false.
Приклад
function User() {}
const tim = new User();
console.log(tim instanceof User); // true
console.log(tim instanceof Object); // true
console.log(tim instanceof Array); // falseПід капотом instanceof перевіряє:
tim.__proto__ === User.prototype
або
tim.__proto__.__proto__ === User.prototype
і так далі, поки не дійде до nullЯк це працює "під капотом"
function instanceOf(obj, Constructor) {
let proto = Object.getPrototypeOf(obj); // починаємо з [[Prototype]]
while (proto) {
if (proto === Constructor.prototype) return true; // знайшли збіг
proto = Object.getPrototypeOf(proto); // рухаємось вгору
}
return false; // дійшли до null - не знайшли
}Саме так instanceof проходить ланцюжок прототипів,
поки не знайде збіг.
Візуально
function Animal() {}
function Dog() {}
Dog.prototype = Object.create(Animal.prototype);
const rex = new Dog();Ланцюжок:
rex → Dog.prototype → Animal.prototype → Object.prototype → nullПеревірки:
console.log(rex instanceof Dog); // true
console.log(rex instanceof Animal); // true
console.log(rex instanceof Object); // trueТому що всі ці прототипи зустрічаються в ланцюжку rex.__proto__.
Приклад із класами (той самий принцип)
class Animal {}
class Dog extends Animal {}
const dog = new Dog();
console.log(dog instanceof Dog); // true
console.log(dog instanceof Animal); // true
console.log(dog instanceof Object); // trueСинтаксис інший, але під капотом - той самий ланцюжок прототипів.
Приклад, де instanceof поверне false
function User() {}
const tim = new User();
Object.setPrototypeOf(tim, null);
console.log(tim instanceof User); // false (ланцюжок обірвався)Якщо об'єкт позбавлений прототипу або ланцюжок не містить User.prototype,
оператор поверне false.
Особливість із різними контекстами (наприклад, iframes)
const arr = [];
console.log(arr instanceof Array); // true
// але в іншому вікні/iframe:
console.log(arr instanceof window.top.Array); // falseТому що у кожного контексту (frame, realm) свій Array.prototype,
і instanceof порівнює саме об'єкт за посиланням, а не за назвою.
Альтернатива: obj.constructor
const user = new User();
console.log(user.constructor === User); // trueАле це ненадійно: властивість constructor можна перевизначити:
user.constructor = null;
console.log(user instanceof User); // все ще trueТому instanceof - безпечніший спосіб.
Підсумок
| Перевірка | Що робить | Використовує |
|---|---|---|
obj instanceof Constructor | Перевіряє, чи є Constructor.prototype у ланцюжку прототипів об'єкта | [[Prototype]] |
| Повертає | true або false | |
Надійніше, ніж obj.constructor | Так | |
| Працює з класами | Так | |
| Чутливий до контексту (iframe) | Так |
Візуальна схема
obj
↑
__proto__ → Constructor.prototype
↑
__proto__ → Object.prototype
↑
nullЯкщо Constructor.prototype зустрічається на цьому шляху,
instanceof поверне true.
В одній фразі:
instanceofперевіряє, чи входитьprototypeконструктора в ланцюжок прототипів об'єкта, рухаючись вгору по__proto__, поки не знайде збіг абоnull.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.