up
This commit is contained in:
parent
f99574f53b
commit
b0976b5253
153 changed files with 590 additions and 533 deletions
|
@ -0,0 +1,7 @@
|
|||
Да, это выглядит достаточно странно, поскольку объект `a` не создавался функцией `B`.
|
||||
|
||||
Но методу `instanceof` на самом деле вообще не важна функция. Он смотрит на её `prototype` и сверяет его с цепочкой `__proto__` объекта.
|
||||
|
||||
В данном случае `a.__proto__ == B.prototype`, поэтому `instanceof` возвращает `true`.
|
||||
|
||||
По логике `instanceof` именно прототип задаёт "тип объекта", поэтому `instanceof` работает именно так.
|
|
@ -0,0 +1,22 @@
|
|||
importance: 5
|
||||
|
||||
---
|
||||
|
||||
# Странное поведение instanceof
|
||||
|
||||
Почему `instanceof` в коде ниже возвращает `true`, ведь объект `a` явно создан не `B()`?
|
||||
|
||||
```js run
|
||||
function A() {}
|
||||
|
||||
function B() {}
|
||||
|
||||
A.prototype = B.prototype = {};
|
||||
|
||||
var a = new A();
|
||||
|
||||
*!*
|
||||
alert( a instanceof B ); // true
|
||||
*/!*
|
||||
```
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
Да, распознает.
|
||||
|
||||
Он проверяет наследование с учётом цепочки прототипов.
|
||||
|
||||
```js run
|
||||
function Animal() {}
|
||||
|
||||
function Rabbit() {}
|
||||
Rabbit.prototype = Object.create(Animal.prototype);
|
||||
|
||||
var rabbit = new Rabbit();
|
||||
|
||||
alert( rabbit instanceof Rabbit ); // true
|
||||
alert( rabbit instanceof Animal ); // true
|
||||
alert( rabbit instanceof Object ); // true
|
||||
```
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
importance: 5
|
||||
|
||||
---
|
||||
|
||||
# Что выведет instanceof?
|
||||
|
||||
В коде ниже создаётся простейшая иерархия классов: `Animal -> Rabbit`.
|
||||
|
||||
Что выведет [instanceof](/instanceof)?
|
||||
|
||||
Распознает ли он `rabbit` как `Animal`, `Rabbit` и к тому же `Object`?
|
||||
|
||||
```js
|
||||
function Animal() {}
|
||||
|
||||
function Rabbit() {}
|
||||
Rabbit.prototype = Object.create(Animal.prototype);
|
||||
|
||||
var rabbit = new Rabbit();
|
||||
|
||||
alert( rabbit instanceof Rabbit );
|
||||
alert( rabbit instanceof Animal );
|
||||
alert( rabbit instanceof Object );
|
||||
```
|
||||
|
82
1-js/9-object-inheritance/11-instanceof/article.md
Normal file
82
1-js/9-object-inheritance/11-instanceof/article.md
Normal file
|
@ -0,0 +1,82 @@
|
|||
# Проверка класса: "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` особенно востребован в случаях, когда мы работаем с иерархиями классов. Это наилучший способ проверить принадлежность тому или иному классу с учётом наследования.
|
Loading…
Add table
Add a link
Reference in a new issue