# 04. instanceof Operator

Вызов `obj instanceof Constructor` возвращает `true`, если объект принадлежит классу `Constructor` или классу, наследующему от него. Оператор `instanceof` требует, чтобы левым операндом был объект, а правым – имя класса объектов. Результатом оператора будет значение `true`, если объект, указанный слева, является экземпляром класса, указанного справа.

```javascript
{} instanceof Object // => true
[] instanceof Array // => true
[] instanceof Object // => true

undefined instanceof Object // => false
null instanceof Object // => false
'abc' instanceof Object // => false
123 instanceof Object // => false

const d = new Date();
d instanceof Date;  // => true
d instanceof Object; // => true
d instanceof Number; //  => false

const a = [1, 2, 3];
a instanceof Array; // => true
a instanceof Object; // => true
a instanceof RegExp; // => false
```

## Prototype chain and `instanceof`

Проверка происходит через сравнение прототипов. Сама по себе функция-конструктор не участвует в процессе проверки! Важна только цепочка прототипов для проверяемого объекта.

Алгоритм проверки `obj instanceof Constructor`:

* Получить `obj.__proto__`
* Сравнить `obj.__proto__` с `Constructor.prototype`
* Если не совпадает, тогда заменить `obj` на `obj.__proto__` и повторить проверку на шаге 2 до тех пор, пока либо не найдется совпадение (результат `true`), либо цепочка прототипов не закончится (результат `false`).

Практически всегда для объектов выражение `obj instanceof Object` вернет `true`, поскольку объект имеет прототип `Object.prototype`. Однако, если объект был создан без прототипа, то нельзя проверить его тип:

```javascript
> Object.create(null) instanceof Object
false
> Object.prototype instanceof Object
false
```

Однако `typeof` корректно распознает тип объекта:

```javascript
> typeof Object.create(null)
'object'
> typeof Object.prototype
'object'
```

## `@@hasInstance` symbol

A method with the key `Symbol.hasInstance` lets an object `C` customize the behavior of the `instanceof` operator. Signature of that method `[Symbol.hasInstance](potentialInstance : any)`.

`obj instanceof Type` is equivalent to `Type[Symbol.hasInstance](obj)`:

```javascript
class Iterable {
  static [Symbol.hasInstance](obj) {
    return typeof obj[Symbol.iterator] === "function";
  }
}
let array = [1, 5, 5];
let string = "Welcome";
let number = 15;
array instanceof Iterable; // => true
string instanceof Iterable; // => true
number instanceof Iterable; // => false
```

`x instanceof C` works as follows in ES6:

* If `C` is not an object, throw a `TypeError`.
* If the method exists, call `C[Symbol.hasInstance](x)`, coerce the result to `boolean` and return it.
* Otherwise, compute and return the result according to the traditional algorithm (`C` must be callable, `C.prototype` in the prototype chain of `x`, etc.).

Особенности:

* Позволяет делать собственные реализации проверки на `instanceof`
* Эта проверка может находится внутри объекта (а не функции-конструктора)

Пример: объекты относятся к одному классу, если у них есть атрибут `foo`:

```javascript
const obj = {
  foo: true,
  [Symbol.hasInstance](inst) {
    return Boolean("foo" in this) === Boolean("foo" in inst);
  }
};

const obj2 = {
  foo: false
};

obj2 instanceof obj;
```
