Оператор instanceof

instanceof проверяет, присутствует ли prototype конструктора в прототипной цепочке объекта, возвращая true или false.

Зачем нужно

instanceof позволяет проверять тип объекта в рантайме: является ли объект экземпляром конкретного класса или его потомка. Это важно при написании полиморфного кода, обработке ошибок и работе с иерархиями классов.

Где используется

  • Проверка типа ошибки в catch-блоке
  • Полиморфизм: разное поведение для разных типов
  • Валидация аргументов функций
  • Паттерн Visitor

Базовый синтаксис

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 — Object в вершине цепочки

console.log(rex instanceof Array);  // false

Как работает

instanceof проходит по [[Prototype Pattern]]-цепочке объекта слева и сравнивает каждое звено с Constructor.prototype:

// Эквивалент instanceof вручную
function myInstanceOf(obj, Constructor) {
  let proto = Object.getPrototypeOf(obj);
  while (proto !== null) {
    if (proto === Constructor.prototype) return true;
    proto = Object.getPrototypeOf(proto);
  }
  return false;
}

console.log(myInstanceOf(rex, Dog));    // true
console.log(myInstanceOf(rex, Animal)); // true

Проверка типов ошибок

function processError(err) {
  if (err instanceof TypeError) {
    console.error('Ошибка типа:', err.message);
  } else if (err instanceof RangeError) {
    console.error('Выход за диапазон:', err.message);
  } else if (err instanceof Error) {
    console.error('Общая ошибка:', err.message);
  }
}

try {
  null.property; // TypeError
} catch (e) {
  processError(e); // 'Ошибка типа: Cannot read properties of null'
}

Использование с пользовательскими классами

class Shape {
  area { return 0; }
}

class Circle extends Shape {
  constructor(r) { super; this.r = r; }
  area { return Math.PI * this.r ** 2; }
}

class Rectangle extends Shape {
  constructor(w, h) { super; this.w = w; this.h = h; }
  area { return this.w * this.h; }
}

function printArea(shape) {
  if (!(shape instanceof Shape)) {
    throw new TypeError('Ожидается экземпляр Shape');
  }
  console.log(`Площадь: ${shape.area.toFixed(2)}`);
}

printArea(new Circle(5));      // Площадь: 78.54
printArea(new Rectangle(3, 4)); // Площадь: 12.00

Symbol.hasInstance — кастомизация

class EvenNumber {
  static [Symbol.hasInstance](value) {
    return typeof value === 'number' && value % 2 === 0;
  }
}

console.log(2 instanceof EvenNumber);  // true
console.log(3 instanceof EvenNumber);  // false
console.log(42 instanceof EvenNumber); // true

Частые ошибки

1. Разные realm'ы (iframe, vm)

// Объект, созданный в iframe, может не пройти instanceof
// из основного документа, даже если класс одинаковый
const arr = new iframe.contentWindow.Array;
arr instanceof Array; // false! Разные Array.prototype

// Для проверки встроенных типов используй:
Array.isArray(arr);            // true — не зависит от realm
Object.prototype.toString().call(arr); // '[object Array]'

2. instanceof с примитивами

console.log('строка' instanceof String); // false — примитив, не объект
console.log(42 instanceof Number);       // false

// typeof для примитивов:
typeof 'строка' === 'string'; // true

3. Изменение prototype после создания объекта

function Foo() {}
const obj = new Foo();
Foo.prototype = {}; // заменили прототип!
console.log(obj instanceof Foo); // false — цепочка разорвана

Связанные темы

Ресурсы