Меню с таймером для анимации
важность: 5
Есть класс Menu . У него может быть два состояния: открыто STATE_OPEN и закрыто STATE_CLOSED . Создайте наследника AnimatingMenu , который добавляет третье состояние STATE_ANIMATING .
При вызове open() состояние меняется на STATE_ANIMATING , а через 1 секунду, по таймеру, открытие завершается вызовом open() родителя.
Вызов close() при необходимости отменяет таймер анимации (назначаемый в open ) и передаёт вызов родительскому close .
Метод showState для нового состояния выводит "анимация" , для остальных – полагается на родителя.
Исходный документ, вместе с тестом
Открыть песочницу для задачи.
К решению
Что содержит constructor?
важность: 5
В коде ниже создаётся простейшая иерархия классов: Animal ‐> Rabbit .
Что содержит свойство rabbit.constructor ? Распознает ли проверка в alert объект как Rabbit ?
function Animal() {} function Rabbit() {}
Rabbit.prototype = Object.create(Animal.prototype); var rabbit = new Rabbit();
alert( rabbit.constructor == Rabbit ); // что выведет?
К решению
Проверка класса: "instanceof"
Оператор 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 ? Так сказать, во избежание.
Итого
Оператор obj instanceof Func проверяет тот факт, что obj является результатом вызова new Func . Он учитывает цепочку proto , поэтому наследование поддерживается.
Оператор instanceof не сможет проверить тип значения, если объект создан в одном окне/фрейме, а проверяется в другом. Это потому, что в каждом окне – своя иерархия объектов. Для точной проверки типов встроенных объектов можно использовать свойство [[Class]] .
Оператор instanceof особенно востребован в случаях, когда мы работаем с иерархиями классов. Это наилучший способ проверить принадлежность тому или иному классу с учётом наследования.
✔ Задачи
Do'stlaringiz bilan baham: |