en.javascript.info/1-js/9-object-inheritance/11-instanceof/article.md
Ilya Kantor b0976b5253 up
2016-11-14 23:41:18 +03:00

82 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Проверка класса: "instanceof"
Оператор `instanceof` позволяет проверить, какому классу принадлежит объект, с учетом прототипного наследования.
[cut]
## Алгоритм работы instanceof [#ref-instanceof]
Вызов `obj instanceof Constructor` возвращает `true`, если объект принадлежит классу `Constructor` или классу, наследующему от него.
Пример использования:
```js run
function Rabbit() {}
*!*
// создаём объект
*/!*
var rabbit = new Rabbit();
// проверяем -- этот объект создан Rabbit?
*!*
alert( rabbit instanceof Rabbit ); // true, верно
*/!*
```
Массив `arr` принадлежит классу `Array`, но также и является объектом `Object`. Это верно, так как массивы наследуют от объектов:
```js run
var arr = [];
alert( arr instanceof Array ); // true
alert( arr instanceof Object ); // true
```
Как это часто бывает в JavaScript, здесь есть ряд тонкостей. Проверка происходит через сравнение прототипов, поэтому в некоторых ситуациях может даже ошибаться!
**Алгоритм проверки `obj instanceof Constructor`:**
1. Получить `obj.__proto__`
2. Сравнить `obj.__proto__` с `Constructor.prototype`
3. Если не совпадает, тогда заменить `obj` на `obj.__proto__` и повторить проверку на шаге 2 до тех пор, пока либо не найдется совпадение (результат `true`), либо цепочка прототипов не закончится (результат `false`).
В проверке `rabbit instanceof Rabbit` совпадение происходит на первом же шаге этого алгоритма, так как: `rabbit.__proto__ == Rabbit.prototype`.
А если рассмотреть `arr instanceof Object`, то совпадение будет найдено на следующем шаге, так как `arr.__proto__.__proto__ == Object.prototype`.
Забавно, что сама функция-конструктор не участвует в процессе проверки! Важна только цепочка прототипов для проверяемого объекта.
Это может приводить к забавному результату и даже ошибкам в проверке при изменении `prototype`, например:
```js run
// Создаём объект rabbit, как обычно
function Rabbit() {}
var rabbit = new Rabbit();
// изменили prototype...
Rabbit.prototype = {};
// ...instanceof перестал работать!
*!*
alert( rabbit instanceof Rabbit ); // false
*/!*
```
Стоит ли говорить, что это один из доводов для того, чтобы никогда не менять `prototype`? Так сказать, во избежание.
```warn header="Не друзья: `instanceof` и фреймы"
Оператор `instanceof` не срабатывает, когда значение приходит из другого окна или фрейма.
Например, массив, который создан в ифрейме и передан родительскому окну -- будет массивом *в том ифрейме*, но не в родительском окне. Проверка `instanceof Array` в родительском окне вернёт `false`.
Вообще, у каждого окна и фрейма -- своя иерархия объектов и свой `window` .
Как правило, эта проблема возникает со встроенными объектами, в этом случае используется проверка внутреннего свойства `[[Class]]`, которое подробнее описано в главе <info:class-instanceof>.
```
## Итого
- Оператор `obj instanceof Func` проверяет тот факт, что `obj` является результатом вызова `new Func`. Он учитывает цепочку `__proto__`, поэтому наследование поддерживается.
- Оператор `instanceof` не сможет проверить тип значения, если объект создан в одном окне/фрейме, а проверяется в другом. Это потому, что в каждом окне -- своя иерархия объектов. Для точной проверки типов встроенных объектов можно использовать свойство `[[Class]]`.
Оператор `instanceof` особенно востребован в случаях, когда мы работаем с иерархиями классов. Это наилучший способ проверить принадлежность тому или иному классу с учётом наследования.