Беларусь, рогачёв |
Классы
Конструктор
Конструктор как обычная функция
Давайте обеспечим наш класс lift конструктором. Правило, согласно которому имя конструктора должно совпадать с именем класса, выполняется и во Флэше. В результате нам придется как-то избегать конфликта имен между объектом - прототипом и конструктором. Но начнем мы все же с конструктора, а проблемы с конфликтом имен, как мы увидим далее, решатся сами собой. Итак, при написании конструктора нам нужно знать, что это обычная функция, принадлежащая тому же объекту, которому должен принадлежать наш класс. Но при этом ключевое слово this будет обращением к объекту нашего класса, а не к объекту -хозяину. Это обеспечивается специальным механизмом вызова конструктора (в процессе выполнения оператора new , подробнее о котором далее). Приведенных только что сведений достаточно, чтобы написать следующий код:
_global.lift = function (minFloor, maxFloor){ this.minFloor = minFloor; this.maxFloor = maxFloor; }
Как мы уже говорили, конструктор будет вызван при создании объекта нашего класса с помощью оператора new . Но откуда оператор new возьмет прототип?
Конструктор как хранилище прототипа
Еще раз посмотрим, какая задача стоит перед нами. У нас имеется имя класса, оно же имя функции- конструктора. Так что оператор new , зная это имя, легко отыщет конструктор. Нет ли какого-то способа прицепить к конструктору прототип, чтобы не искать прототип отдельно?
Конечно же, есть! Объект функции- конструктора может содержать дополнительные поля, в одно из которых вполне можно положить ссылку на прототип. Именно так все и делается во Флэш МХ. У функции можно завести поле prototype и положить туда ссылку на объект - прототип. В тех случаях, когда функция используется в качестве конструктора (при вызове через оператор new ), оператор new в качестве прототипа использует именно тот объект, ссылка на который лежит в поле prototype функции- конструктора. Так что к уже написанному коду, определяющему объект lift, нам надо добавить вот что:
// Конструктор _global.lift = function (minFloor, maxFloor){ this.minFloor = minFloor; this.maxFloor = maxFloor; } // Ссылка на прототип _global.lift.prototype = lift; // Создаем 2 объекта l1 = new _global.lift(2, 5); l2 = new _global.lift(0, 3); // Тестируем trace("l1:"); l1.goto(4); trace("l2:") l2.goto(4);
После запуска этого кода получим в консоли:
l1: ----------- Закрываем двери. Этаж 1 Этаж 2 Этаж 3 Этаж 4 Открываем двери. ----------- l2: ----------- Закрываем двери. Этаж 1 Этаж 2 Этаж 3 Открываем двери. -----------
Можно сделать следующие комментарии по поводу нашей работы. Во-первых, в конструкторе имеется ошибка: он не устанавливает начальный этаж, в результате лифт номер один поехал на четвертый с первого этажа, хотя минимальным является второй. Во-вторых, нам пришлось использовать явное указание на то, что конструктор берется из объекта _global. Иначе нам мешал бы уже имеющийся в _root (в котором был размещен наш код) объект по имени lift. Логично было бы не создавать конфликта имен, а сразу помещать все свойства и методы в prototype, тем более, что пустой объект, в который они будут добавлены, создается автоматически и надпись, аналогичная lift = {}; необязательна.