Оператор instanceof
позволяет проверить, какому классу принадлежит объект, с учетом прототипного наследования.
Алгоритм работы instanceof
Вызов obj instanceof Constructor
возвращает true
, если объект принадлежит классу Constructor
или классу, наследующему от него.
Пример использования:
function Rabbit() {}
// создаём объект
var rabbit = new Rabbit();
// проверяем -- этот объект создан Rabbit?
alert( rabbit instanceof Rabbit ); // true, верно
Массив arr
принадлежит классу Array
, но также и является объектом Object
. Это верно, так как массивы наследуют от объектов:
var arr = [];
alert( arr instanceof Array ); // true
alert( arr instanceof Object ); // true
Как это часто бывает в JavaScript, здесь есть ряд тонкостей. Проверка происходит через сравнение прототипов, поэтому в некоторых ситуациях может даже ошибаться!
Алгоритм проверки obj instanceof Constructor
:
- Получить
obj.__proto__
- Сравнить
obj.__proto__
сConstructor.prototype
- Если не совпадает, тогда заменить
obj
наobj.__proto__
и повторить проверку на шаге 2 до тех пор, пока либо не найдется совпадение (результатtrue
), либо цепочка прототипов не закончится (результатfalse
).
В проверке rabbit instanceof Rabbit
совпадение происходит на первом же шаге этого алгоритма, так как: rabbit.__proto__ == Rabbit.prototype
.
А если рассмотреть arr instanceof Object
, то совпадение будет найдено на следующем шаге, так как arr.__proto__.__proto__ == Object.prototype
.
Забавно, что сама функция-конструктор не участвует в процессе проверки! Важна только цепочка прототипов для проверяемого объекта.
Это может приводить к забавному результату и даже ошибкам в проверке при изменении prototype
, например:
// Создаём объект rabbit, как обычно
function Rabbit() {}
var rabbit = new Rabbit();
// изменили prototype...
Rabbit.prototype = {};
// ...instanceof перестал работать!
alert( rabbit instanceof Rabbit ); // false
Стоит ли говорить, что это один из доводов для того, чтобы никогда не менять prototype
? Так сказать, во избежание.
instanceof
и фреймыОператор instanceof
не срабатывает, когда значение приходит из другого окна или фрейма.
Например, массив, который создан в ифрейме и передан родительскому окну – будет массивом в том ифрейме, но не в родительском окне. Проверка instanceof Array
в родительском окне вернёт false
.
Вообще, у каждого окна и фрейма – своя иерархия объектов и свой window
.
Как правило, эта проблема возникает со встроенными объектами, в этом случае используется проверка внутреннего свойства [[Class]]
, которое подробнее описано в главе Типы данных: [[Class]], instanceof и утки.
Итого
- Оператор
obj instanceof Func
проверяет тот факт, чтоobj
является результатом вызоваnew Func
. Он учитывает цепочку__proto__
, поэтому наследование поддерживается. - Оператор
instanceof
не сможет проверить тип значения, если объект создан в одном окне/фрейме, а проверяется в другом. Это потому, что в каждом окне – своя иерархия объектов. Для точной проверки типов встроенных объектов можно использовать свойство[[Class]]
.
Оператор instanceof
особенно востребован в случаях, когда мы работаем с иерархиями классов. Это наилучший способ проверить принадлежность тому или иному классу с учётом наследования.
Комментарии
<code>
, для нескольких строк кода — тег<pre>
, если больше 10 строк — ссылку на песочницу (plnkr, JSBin, codepen…)