Дострочное пересдача экзамена
|
Создание и модификация объектов
Отношения "родитель-потомок"
Когда вы помещаете монтажный стол (то есть, экземпляр объекта MovieClip ) на другой монтажный стол (другой экземпляр) – вам приходилось делать это с фильмами-символами – вы создаете отношения родитель-потомок (см. Урок 3 – Об адресации). Тот же принцип применим и к объектам. Продолжая наш предыдущий пример, давайте рассмотрим следующее:
person1.head.memories
Здесь head является дочерним объектом по отношению к person1, а memories – потомок и head, и person1 (таким образом, head – родитель memories, а person1 – предок head и memories ).
Теперь внимание: следует помнить о том, что если что-то происходит с родителем, то же случается и с его потомками – что мы и продемонстрируем в следующем упражнении.
- Откройте файл object1.fla из папки Lesson06/Assets. Откройте панель Действия, выделите кадр 1. Удалите действие trace, добавленное на шаге 9 предыдущего упражнения и добавьте в конец скрипта следующие строки:
delete person1.head; trace(person1.head); trace(person1.head.memories[1]); trace(person1.name);
Первое действие удаляет head из person1. Последующие действия trace позволяют нам увидеть, как это повлияло на наш объект.
- Командой Управление > Проверить фильм (Control > Test Movie) запустите тест проекта.
Откроется окно Выход (Output), и в нем отобразится:
undefined undefined Justin
Мы видим, что person1.head теперь undefined, как и memories[1], находившийся внутри head. Будучи потомком head массив memories был удален вместе со своим родителем. Однако на прочие свойства объекта person1 это не повлияло – что и продемонстрировало последнее действие trace, вернув значение person1.name.
Как видите, правильно сконструированный объект реагирует на внешние обстоятельства почти так же, как объекты из реальной жизни. А в соединении с действиями, вызывающими визуальные изменения в фильме, (скоро мы до этого дойдем) объекты способны и на большее.
- Закройте тестовый фильм и вернитесь в среду разработки. Выделите кадр 1, в панели Действия добавьте в конец скрипта, сразу после строки trace(person1.name); следующие строки:
person1.head = new Object(); trace(person1.head); trace(person1.head.memories[1]);
Первая строка вновь добавляет объект head к person1. Последующие действия trace позволяют нам увидеть результат. Учтите, что эти три строки скрипта мы поместили после четырех строк, добавленных на первом шаге. Таким образом, при тестировании проекта окно Выход вновь покажет нам результат удаления person1.head ; но на этот раз за ним будет следовать результат возвращения свойства head.
- Командой Управление > Проверить фильм (Control > Test Movie) запустите тест проекта.
Откроется окно Выход (Output), и в нем отобразится:
undefined undefined Justin [object Object] undefined
Три первых выведенных строки – те же, что мы видели на шаге 2. А две последние показывают, что получилось после возвращения person1 свойства head. В результате person1.head отображено как [object Object], и это значит, что объект head опять существует (и является экземпляром объекта Object), однако person1.head.memories[1] остался undefined. Причина в том, что массив person1.head.memories был удален до этого (в результате удаления person1.head ), и "забыт" – выгружен из памяти компьютера (вместе, кстати, со свойством eyes, которое также было частью объекта head ). Когда мы вновь добавили свойство head, компьютер уже не "вспомнил" ни массива memories, ни свойства eyes. Чтобы восстановить их, пришлось бы создавать эти элементы заново и заново помещать в них данные.
- Закройте тестовый фильм и сохраните свою работу как object2.fla.
Наша работа с этим файлом завершена. В следующем разделе мы продолжим изучение объектов – и теперь подойдем с другой стороны.
Описание нового класса и создание экземпляров этого класса
До сего времени мы использовали экземпляр родового объекта Object для демонстрации принципов действия нашего объекта person1. Теперь настало время перейти на следующий уровень механики объектов: создать собственный класс, который мы опишем в этом упражнении как класс Person. Этот класс послужит образцом, "чертежом" для создания новых экземпляров "персон" – вы убедитесь, что такой способ более эффективен для создания person1 и ему подобных.
Примечание В предыдущих упражнениях мы использовали объект Object главным образом ради демонстрации общей концепции объектов. На самом деле объект Object может найти действительно ценное применение в реальных проектах, хотя это – весьма общее решение, которое подойдет не для всякого приложения.
Как и в предыдущих упражнениях, здесь, изучая "теоретическую часть", мы будем частенько пользоваться действием trace.
- Откройте Flash и выполните команду Файл > Новый (File > New), чтобы создать новый файл проекта. Откройте панель Действия, выделите кадр 1 и ведите следующий скрипт:
Person = function(){ }
Да, это очень похоже на объявление функции – это и называется конструктор функции, но именно с этого начинается описание класса.
Примечание В ходе дальнейшего обсуждения темы термины конструктор функции и описание класса будут означать одно и то же.
Обычное объявление функции и конструктор функции (описание класса) имеют одинаковый синтаксис, однако доступ к ним осуществляется по-разному. Через минуту мы разъясним все это детально, а пока давайте посмотрим на два примера. В первом случае функция выполняется как функция; во втором – создается экземпляр класса Person:
Person(); //выполняется как функция person1 = new Person(); //создается экземпляр класса Person
Примечание Хотя описание класса выглядит, как функция, его следует рассматривать именно как описание класса. Использовать один и тот же блок кода обоими способами не советуем.
Снова повторим, что описание класса мы рассматриваем как чертеж, или шаблон, для создания экземпляров этого класса. Внутри фигурных скобок мы помещаем характеристики, описывающие этот класс объектов. Пока что наш класс Person не имеет никаких характеристик (свойств), поэтому давайте опишем этот класс, как в нашем предыдущем примере.
- Дополните описание класса Person следующим образом:
Person = function(){ this.name = "Justin"; this.age = 16; this.legs = 2; this.head = new Object(); this.head.eyes = 2; this.head.memories = new Array(); }
Наше описание класса завершено. Далее мы поговорим о том, как его использовать и что означает this в контексте описания класса. Также мы покажем, как создавать экземпляры нашего нового класса.
Совет Возможно, вы обратили внимание, что в описании имя нового класса Person начинается с заглавной буквы. Хотя это не обязательно, такова общая практика. Имена экземпляров класса, напротив, начинаются обычно с маленькой буквы. Соблюдение этого простого правила позволит сделать ваши скрипты более удобочитаемыми и понятными.
- Добавьте в конец скрипта следующую строку:
person1 = new Person();
Этим создается экземпляр объекта Person с именем person1.
- Командой Управление > Проверить фильм (Control > Test Movie) запустите тест проекта. Когда на экране появится среда тестирования, выполните команду Отладка > Список переменных (Debug > List Variables).
Когда откроется окно Выход ( Output ), в нем отобразится следующая информация:
Variable _level0.person1 = [object #2] { name:"Justin", age:16, legs:2, head:[object #3, class 'Object'] { eyes:2, memories:[object #4, class 'Array'] [] } }
Это – информация об экземпляре person1, который мы создали действием, добавленным на предыдущем шаге. Как определяет наш класс Person, экземпляр person1 имеет имя "Justin", возраст 16, две ноги и так далее.
Важно понимать, что команда person1 = new Person() ; создает экземпляр, свойства которого определены классом Person. Все происходит очень просто: выполняя эту строку кода, ActionScript понимает, что настало время создать новый экземпляр класса Person. Тогда создается временный объект (объект Activation) и отсылается к описанию класса Person, запрограммированному ранее (все это происходит автоматически и внешне никак не проявляется). Объект Activation, поначалу совершенно бесформенный, "проходит" через описание класса, где получает различные свойства класса ( name, age, legs и так далее). В ходе этого процесса временный объект Activation для адресации пользуется термином this, как указано в описании класса. Например, в описании класса встретилась строка:
this.age = 16;
Это значит, что когда объект Activation будет проходить через нее, его свойству age должно быть присвоено значение 16. Процесс создания экземпляра можно представить как движение объекта Activation по сборочной линии конвейера – к нему добавляются по очереди части и он движется дальше. Когда процесс сборки завершен, объект активации получает имя (в данном случае person1 ), и все – он готов к использованию.
Итак, мы описали класс Person и знаем, как создавать его экземпляры, однако все эти экземпляры будут совершенно идентичными. Все дело в том, что так был определен наш класс Person – все его экземпляры будут иметь имя "Justin", возраст 16 и так далее. Хотелось бы, чтоб наш класс Person был способен на что-то большее, чем творить собственных клонов, а потому давайте внесем в описание класса некоторые изменения, чтобы можно было создавать экземпляры с различающимися значениями свойств.
- Закройте тестовый фильм и вернитесь в среду разработки. Выделите кадр 1, и в панели Действия измените описание класса Person следующим образом:
Person = function(name, age){ this.name = name; this.age = age; this.legs = 2; this.head = new Object() this.head.eyes = 2; this.head.memories = new Array(); }
Подобно объявлению обычной функции, в нашем описании класса Person теперь указано два аргумента: name и age. Обратите внимание – те же самые значения указаны теперь и в первых двух строках описания класса. Это позволит нам создавать экземпляры класса Person, имеющие уникальные значения свойств.
- Измените последнюю строку скрипта, а после нее добавьте еще одну:
person1 = new Person ("Justin", 16); person2 = new Person ("Derek", 29);
Эти два действия создают два экземпляра класса Person. Эти экземпляры имеют разные значения свойств name и age – обновленное описание класса Person позволяет это. Чтобы задать свойства нового экземпляра, мы можем передавать конструктору строки, числа и даже имена объектов.
Теперь хотелось бы упростить создание экземпляров класса Person, чтобы это можно было сделать с любого монтажного стола без указания пути, подобно встроенным объектам Flash. Для этого мы должны сделать наше описание класса глобальным.
- Измените описание класса Person следующим образом:
_global.Person = function(name, age){ this.name = name; this.age = age; this.legs = 2; this.head = new Object() this.head.eyes = 2; this.head.memories = new Array(); }
Обратите внимание на _global в первой строке скрипта: именно это слово позволит создавать экземпляры класса Person с любого монтажного стола, просто используя такой конструктор:
new Person();
Если бы слова _global не было, и описание класса находилось бы, скажем, на основном монтажном столе, то с других монтажных столов пришлось бы использовать следующий синтаксис:
new _root.Person();
Примечание Даже если вы, используя _global, сделаете класс доступным для всех монтажных столов без адресации, отдельные экземпляры все-таки будут находиться на монтажном столе, содержащем скрипт, создавший этот экземпляр. Допустим, вы создаете экземпляр объекта Person с именем myBuddy, причем скрипт, создающий экземпляр, находится в _root.myMovieClip. Тогда абсолютный адрес экземпляра myBuddy будет _root.myMovieClip.myBuddy. Конечно, при желании можно сделать глобальным и экземпляр, использовав такой синтаксис: _global.myBuddy = new Person("Dennis", 27);.
- Сохраните свою работу как class1.fla.
В следующем упражнении мы продолжим работать с этим файлом. Мы теперь умеем создавать экземпляры класса Person, однако этого мало – нужно подумать о его "тонкой настройке" в случае необходимости, а для этого требуется освоить такую мощную штуку, как объект-прототип (звучит жутковато, правда?).