
- •Оглавление
- •Вступление
- •Глава 1. Язык сценариев. ActionScript: начальные сведения
- •Проект 1: Прыгающий мяч (программная анимация)
- •1.1. Среда разработки ActionScript: настройка и приемы работы
- •1.1.1. Различие между стандартной и профессиональной версиями Flash
- •1.1.2. Панель Actions
- •1.1.3. Режим упрощенного ввода кода. Панель Behaviors
- •1.1.4. Как упростить создание кода на панели Actions
- •1.1.5. Типы сценариев
- •1.1.6. Централизация кода
- •1.1.7. Инструменты работы с кодом
- •1.1.8. Настройки стиля кода
- •1.1.9. Сохранение ActionScript-кода
- •1.1.10. Функция trace() и панель Output
- •1.1.11. Справочная информация
- •1.2. Синтаксис ActionScript
- •1.2.1. Пробельные символы
- •1.2.2. Завершение предложений
- •1.2.3. Чувствительность к регистру
- •1.2.4. Зарезервированные слова ActionScript
- •1.2.5. Принципы присвоения имен
- •1.2.6. Комментарии
- •1.3. Основные понятия
- •1.3.2. ActionScript как скриптовый язык Flash-плейера
- •1.3.3. Интерпретатор ActionScript. Flash-ассемблер
- •1.3.4. Символы и экземпляры символов
- •1.3.5. Переменные
- •1.3.6. Функции
- •1.3.7. Условные предложения
- •1.3.8. Циклы
- •1.3.9. Массивы
- •1.3.10. Объектная модель ActionScript
- •1.3.11. Свойства _root, _parent, Leveln и ключевое слово this
- •1.3.12. Области видимости кода
- •1.3.1. ЕСМА-262 как основа ActionScript
- •Глава 2. Типы данных
- •2.3. Математические функции и константы. Объект Math
- •2.3.1. Особенности реализации математических функций
- •2.3.2. Возведение в степень и вычисление квадратного корня
- •2.3.3. Экспонента и натуральный логарифм
- •2.3.5. Случайные числа
- •2.3.6. Округление до целого числа
- •2.3.7. Сравнение пары чисел
- •2.3.8. Тригонометрические функции
- •2.3.9. Математические константы
- •2.4. Строки (тип string)
- •2.4.1. Создание строк
- •2.4.2. Элементарные операции со строками
- •2.4.3. Класс String
- •2.4.4. Определение длины строки. Свойство lengths
- •2.4.5. Соединение строк. Метод concat()
- •2.4.6. Выделение символа строки по индексу. Метод charAt()
- •2.4.7. Поиск в строке. Методы indexOf() и lastIndexOff()
- •2.4.8. Извлечение подстроки. Методы substring(), substr(), slice()
- •2.4.9. Преобразование строк в массивы. Метод split()
- •2.4.12. Преобразование строк в идентификаторы. Функция eval()
- •2.4.13. Текстовые поля
- •2.5. Кодировка символов. Уникод во Flash
- •2.5.1. Немного истории
- •2.5.2. Поддержка уникода Flash-плейером
- •2.5.3. Поддержка уникода средой разработки
- •2.5.4. Добавление символов уникода
- •2.6. Логические величины (тип boolean)
- •2.6.1. Класс Boolean
- •2.7. Тип undefined
- •2.8. Тип null
- •2.9. Объекты (тип object)
- •2.9.1. Атрибуты свойств
- •2.9.2. Изменение атрибутов свойств. Функция ASSetPropFlags()
- •2.10. Клипы (тип movieclip)
- •2.11. Преобразование типов данных
- •2.11.1. Правила преобразования типов
- •2.11.2. Автоматическое преобразование типов
- •2.12. Строгая типизация в ActionScript
- •Проект 2: Калькулятор
- •2.1. Определение типа объекта данных
- •2.2. Числа (тип number)
- •2.2.1. Виды чисел в ActionScript
- •2.2.2. Особенности представления чисел
- •2.2.3. Операции с числами
- •2.2.4. Класс Number — методы и свойства
- •2.2.5. Преобразование строк в числа. Функции parseInt() и parseFloat()
- •Глава 3. Переменные
- •3.1. Создание переменных
- •3.2. Особенности типизации переменных
- •3.3. Локальные переменные функций
- •3.4. Глобальные переменные
- •3.5. Особенности операции присваивания
- •3.6. Есть ли переменные в ActionScript?
- •3.7. Удаление переменных
- •Проект 3: Пружинный маятник
- •Глава 4. Функции
- •4.1. Создание функций
- •4.2. Вызов функций
- •4.3. Предложение return
- •4.4. Рекурсия
- •4.5. Особенности цепочки областей видимости функций
- •4.6. Объект arguments
- •4.6.1. Формальные параметры и объект arguments
- •4.6.2. Свойства объекта arguments
- •4.7. Особенности передачи в функции составных объектов данных
- •4.8. Функции как объекты
- •4.8.1. Класс Function
- •4.8.2. Свойство prototype
- •4.8.3. Методы вызова функции
- •4.9. Функции на стадии выполнения. Объект активации
- •Проект 4: Крестики-нолики
- •Глава 5. Операторы
- •5.1. Виды операторов
- •5.2. Иерархия операций
- •5.3. Сочетательность операций
- •5.4. Арифметические операторы
- •5.5. Операторы присваивания
- •5.5.1. Оператор =
- •5.5.2. Операторы присваивания с модификацией
- •5.5.3. Инкрементирование и декрементирование
- •5.6. Операторы равенства и сравнения
- •5.6.1. Операторы равенства
- •5.6.2. Операторы сравнения
- •5.7. Логические операторы
- •5.8. Условный оператор (?:)
- •5.9. Служебные операторы
- •5.9.1. Инициализаторы литералов
- •5.9.2. Оператор группирования
- •5.9.3. Операторы доступа к свойствам
- •5.9.4. Оператор вызова функции
- •5.9.5. Оператор new
- •5.9.6. Оператор super
- •5.9.7. Оператор delete
- •5.9.8. Оператор typeof
- •5.9.9. Оператор instanceof
- •5.9.10. Оператор void
- •5.9.11. Оператор «запятая»
- •5.10. Поразрядные операторы
- •5.10.1. Логические поразрядные операторы
- •5.10.2. Операторы поразрядного сдвига
- •Проект 5: 3D-конструктор
- •Глава 6. Предложения
- •6.1. Блок предложений
- •6.2. Предложения var и function
- •6.3. Предложения выражений и пустые предложения
- •6.4. Предложение return
- •6.5. Предложение with
- •6.6. Условные предложения
- •6.6.1. Предложение if
- •6.6.2. Предложение switch
- •6.7. Циклы
- •6.7.1. Циклы с предусловием (while и do—while)
- •6.7.2. Цикл с параметром (for)
- •6.7.4. Предложения break и continue
- •6.7.5. Ограничение на время выполнения кода
- •6.7.6. Циклы события onEnterFrame и временной диаграммы
- •6.7.7. Циклический вызов функций. Функция setInterval()
- •Проект 6: Тетрис
- •Глава 7. Массивы (класс Array)
- •7.1. Создание массивов
- •7.2. Извлечение и переопределение элементов массива
- •7.3. Длина массива. Свойство length
- •7.4. Добавление элементов в массив
- •7.5. Удаление элементов массива
- •7.6. Слияние массивов
- •7.7. Выделение фрагмента массива
- •7.8. Инверсия массива
- •7.9. Сортировка массива
- •7.10. Преобразование массива в строку
- •7.11. Многомерные массивы
- •7.13. Особенности реализации массивов в ActionScript
- •Проект 7: Пиксельное табло
- •Глава 8. События
- •8.1. Модель событий Генератор—Листенеры
- •8.1.1. Обработчики событий
- •8.1.2. Листенеры
- •8.2. Событийные методы
- •8.3. Модель событий Flash 5
- •8.4. Обновление экрана при событиях
- •Проект 8: Создаем события сами
- •Глава 9. Объектно-ориентированное программирование
- •9.2.1. Объекты
- •9.2.2. Свойства
- •9.2.3. Методы
- •9.2.4. Классы
- •9.2.5. Наследование
- •9.2.6. Создание надклассов и подклассов
- •9.2.7. Концепция создания надклассов Flash 6
- •9.2.8. Оператор super
- •9.2.9. Свойства и методы конструктора класса
- •9.2.10. Определение принадлежности объекта к классу
- •9.2.11. Цепочка областей видимости. Объект Global
- •9.3. Класс Object
- •9.3.1. Создание объектов класса Object
- •9.3.2. Метод registerClass(). Выделение экземпляров клипа в класс
- •9.3.3. Метод addProperty(). Свойства типа getter/setter
- •9.3.4. Методы watch() и unwatch(). События изменений свойств
- •9.3.5. Прочие методы класса Object
- •9.4.1. Создание классов
- •9.4.2. Задание наследуемых свойств и методов класса
- •9.4.3. Конструктор класса. Инициализация собственных свойств и методов объектов
- •9.4.4. Особенности задания методов в AciionScript2.0
- •9.4.5. Статичные члены класса
- •9.4.7. Динамические классы
- •9.4.8. Наследование
- •9.4.9. Интерфейсы
- •9.4.10. Свойства типа getter/setter
- •9.4.11. Выделение экземпляров символа в подкласс
- •9.4.12. Особенности контроля на этапе компиляции
- •9.4.13. Особенности импорта внешних классов
- •9.4.14. Пакеты
- •9.4.15. Встроенные классы. Директива intrinsic
- •Проект 9: Модель идеального газа
- •Глава 10. Клипы
- •10.1. Глобальные функции и свойства
- •10.2. Отличия клипов от объектов
- •10.2.1. Свойства клипов
- •10.3. Клипы как носители кода
- •10.3.1. Последовательность выполнения кода
- •10.3.2. Особенности использования свойств и методов класса MovieClip
- •10.4. Особенности основной временной диаграммы _root
- •10.5. Создание экземпляров клипов
- •10.5.1. Метод duplicateMovieClip()
- •10.5.3. Метод createEmptyMovieClip(). Создание пустого клипа
- •10.6. Виртуальные слои клипов
- •10.6.1. Изменение глубины клипа. Метод swapDepths()
- •10.7. Импорт внешних фильмов и изображений
- •10.7.2. Импорт внешних фильмов при помощи функций loadMovie() и loadMovieNum()
- •10.7.3. Импорт изображений
- •10.7.4. Импорт фильмов и изображений при помощи класса MovieClipLoader
- •10.7.5. Создание предзагрузчиков
- •10.7.6. Кэширование swf-фильмов
- •10.7.7. Изменение глубины основной временной диаграммы
- •10.7.8. Доступ из одного фильма к объектам другого
- •10.7.9. Обобщенные библиотеки
- •10.8. Имена экземпляров клипов
- •10.9. Ссылки на клипы
- •10.9.1. Свойство _lockroot
- •10.9.2. Определение пути к клипу
- •10.9.3. Инструмент Insert Target Path
- •10.10. Система координат клипов
- •10.10.1. Свойство _x и _y
- •10.10.2. Пересчет координат из одной системы в другую
- •10.10.3. Масштаб осей
- •10.10.4. Размер клипа
- •10.10.5. Границы клипа
- •10.10.6. Поворот системы координат
- •10.11. Прозрачность и видимость клипа
- •10.11.1. Свойство _alpha
- •10.11.2. Свойство _visible
- •10.12. Перемещаемые клипы. Метод startDrag()
- •10.12.1. Свойство _droptarget
- •10.13. Коллизии клипов. Метод hitTest()
- •10.13.1. Определение пересечения двух клипов
- •10.13.2. Определение принадлежности точки к клипу
- •10.13.3. Определение коллизии клипов с использованием поточечного перебора
- •10.14. Управление временной диаграммой
- •10.14.1. Начало и остановка проигрывания клипа
- •10.14.2. Переход на новый кадр
- •10.14.3. Определение номера проигрываемого кадра
- •10.15. Программные маски
- •10.16. Удаление экземпляров клипов и фильмов
- •10.16.1. Удаление экземпляров. Метод removeMovieClip()
- •10.16.2. Выгрузка содержимого экземпляров. Метод unloadMovie()
- •10.16.3. Выгрузка фильмов
- •10.17. События
- •10.17.1. Создание обработчиков событий в стиле Flash 5
- •10.17.2. Событие смены кадров (onEnterFrame)
- •10.17.3. Событие загрузки клипа (onLoad)
- •10.17.4. Событие выгрузки клипа (onUnload)
- •10.17.5. Событие поступления данных (onData)
- •10.17.6. События мыши (onMouseDown, onMouseUp, onMouseMove)
- •10.17.7. События клавиатуры (onKeyDown, onKeyUp)
- •10.17.8. «Кнопочные» события
- •10.17.9. События фокуса (onSetFocus, onKillFocus)
- •10.18. Программное рисование
- •10.18.1. Рисование прямыми отрезками
- •10.18.2. Рисование фрагментами парабол
- •10.18.3. Однородная заливка
- •10.18.4. Градиентная заливка
- •10.18.5. Удаление программной графики
- •10.19. Управление цветом клипов. Класс Color
- •10.19.1. Цветовые модели
- •10.19.2. Задание формулы цвета
- •10.19.3. Задание цвета клипа. Метод setRGB()
- •10.19.4. Цветовые трансформации. Метод setTransform()
- •Проект 10: Рисование 3D-объектов
- •Глава 11. Кнопки
- •11.1. Создание кнопок
- •11.2. Сходства и различия кнопок и клипов
- •11.3. События кнопок
- •11.3.1. Особенности событий кнопок
- •11.3.2. События кнопок в стиле Flash 5
- •11.4. Режим элемента меню
- •11.5. Вид указателя мыши
- •11.6. Отключение кнопок
- •11.7. Управление кнопками при помощи клавиатуры
- •11.7.1. Динамическое наведение фокуса
- •11.7.2. Свойство _focusrect
- •11.7.3. События onSetFocus и onKillFocus
- •11.7.4. Задание маршрута клавиатурного обхода
- •11.7.5. Особенности клавиатурного обхода и программного фокуса в случае клипов
- •11.8. Клипы как кнопки
- •Проект 11: Факел
- •Глава 12. Работа с мышью и клавиатурой
- •12.1. Работа с мышью
- •12.1.1. Определение координат указателя мыши
- •12.1.2. События мыши
- •12.1.3. Скрытие указателя мыши
- •12.1.4. Правая клавиша мыши
- •12.1.5. Определение выхода указателя мыши за пределы окна плейера
- •12.2. Контекстное меню
- •12.2.1. Настройка контекстного меню. Класс ContextMenu
- •12.2.2. Введение в контекстное меню собственных команд
- •12.3. Работа с клавиатурой
- •12.3.1. Особенности событий клавиатуры
- •12.3.2. События onKeyDown и onKeyUp
- •12.3.3. Определение кода нажатой клавиши. Метод getCode()
- •12.3.4. Определение кода введенного символа. Метод getAscii()
- •12.3.5. Проверка нажатия клавиши. Метод isDown()
- •12.3.6. Проверка активности специальных режимов. Метод isToggled()
- •Проект 12: Эластики
- •Глава 13. Работа с текстом
- •13.1. Создание текстовых полей
- •13.1.1. Создание текстовых полей при помощи инструмента Text
- •13.1.2. Переменная поля
- •13.1.3. Динамическое создание текстовых полей
- •13.2. Удаление текстовых полей
- •13.3. Текстовые поля как визуальные объекты
- •13.4. Задание и извлечение текста поля
- •13.5. Настройка текстового поля
- •13.5.1. Управление размером поля
- •13.5.2. Рамка и задний фон
- •13.5.3. Поля однострочные и многострочные
- •13.5.4. Ограничение на количество символов
- •13.5.5. Поле паролей
- •13.5.6. Ограничение на вводимые символы
- •13.5.7. Выделение текста поля
- •13.6. Настройка стиля текста. Класс TextFormat
- •13.6.1. Задание гарнитуры
- •13.6.2. Размер шрифта
- •13.6.3. Цвет шрифта
- •13.6.4. Начертание шрифта
- •13.6.5. Выключка
- •13.6.6. Подчеркнутый шрифт
- •13.6.7. Гиперссылки
- •13.6.8. Форматирование текста
- •13.6.9. Определение размерных параметров текста
- •13.7. Работа со шрифтами
- •13.7.1. Шрифты системные и встроенные
- •13.7.2. Ненаправленные гарнитуры
- •13.7.3. Особенности встраивания шрифтов
- •13.7.4. Встраивание в фильм целого шрифта
- •13.7.5. Встраивание глифов отдельных символов и последовательностей символов
- •13.7.6. Проблема читабельности при отображении мелкого текста
- •13.8. Событие onChanged
- •13.9. Прокрутка текстовых полей
- •13.10. Работа с фокусом
- •13.11. Форматирование текста при помощи HTML
- •13.11.5. Тег <FONT> ... </FONT>
- •13.11.10. Тег <TEXTFORMAT> ... <TEXTFORMAT>
- •13.11.11. Тег <SPAN> ... </SPAN>
- •13.11.13. Автоматическое удаление пробелов. Свойство condenseWhite
- •13.12. Форматирование текста с использованием каскадных таблиц стиля (CSS)
- •13.12.1. Основные положения технологии CSS
- •13.12.2. Создание объекта таблиц стиля
- •13.12.3. Применение объекта стиля к текстовому полю
- •13.12.4. Элементы CSS, поддерживаемые Flash-плейером
- •13.13. Работа с выделением. Объект Selection
- •13.13.1. Управление фокусом поля. Методы getFocus() и setFocus()
- •13.13.2. Событие изменения фокуса (onSetFocus)
- •13.13.4. Определение и задание положения курсора ввода
- •13.13.5. Динамическое задание выделения. Метод setSelection()
- •13.13.6. Динамическая замена выделенного текста. Метод replaceSel()
- •13.14. Работа со статичным текстом. Объект TextSnapshot
- •13.14.1. Создание объектов класса TextSnapshot
- •13.14.2. Считывание текста статичных полей
- •13.14.3. Поиск строки в статичном тексте
- •13.14.4. Программное выделение статичного текста
- •13.14.5. Определение ближайшего к точке символа статичного текста
- •13.15. Копирование текста в буфер обмена
- •13.16. Поддержка многоязычности. Панель Strings
- •Проект 13: Текстовые эффекты
- •Глава 14. Время и дата
- •14.1. Основные понятия теории измерения времени
- •14.2. Компьютерное время
- •14.3. Класс Date
- •14.3.1. Создание объектов класса Date
- •14.3.2. Методы класса Date
- •14.4. Определение времени, прошедшего с начала проигрывания фильма
- •Проект 14: Программные часы
- •Глава 15. Работа со звуком
- •15.1. Основные понятия теории цифрового звука
- •15.1.1. Частота дискретизации
- •15.1.2. Разрядность выборок
- •15.1.3. Количество каналов
- •15.1.4. Алгоритмы компрессии
- •15.1.5. Форматы хранения
- •15.2. Событийный (event) и потоковый (stream) звук
- •15.3. Операции со звуком без использования программирования
- •15.4. Создание объектов класса Sound
- •15.5. Динамическое присоединение звука. Метод attachSound()
- •15.6. Импортирование внешних МР3-файлов
- •15.6.1. Метод loadSound()
- •15.6.2. Отслеживание окончания загрузки. Событие onLoad
- •15.6.3. Создание предзагрузчиков для импортируемых звуков
- •15.7. Управление воспроизведением звуков
- •15.7.1. Запуск воспроизведения. Метод start()
- •15.7.3. Событие onSoundComplete
- •15.8. Свойства position и duration
- •15.9. Управление параметрами воспроизведения
- •15.9.1. Громкость звука
- •15.9.2. Баланс
- •15.9.3. Детальное управление стереозвучанием. Метод setTransform()
- •15.10. Чтение ID3-тегов МР3-звуков
- •Проект 15: МР3-плейер
- •Глава 16. Взаимодействие с локальным окружением
- •16.1. Взаимодействие с импортированными фильмами
- •16.2. Взаимодействие с плейером
- •16.2.1. Определение версии и типа плейера
- •16.2.2. Режимы масштабирования
- •16.2.3. Типы выравнивания
- •16.2.4. Определение размеров фильма и величины окна плейера
- •16.2.5. Событие onResize
- •16.2.6. Цвет фона
- •16.2.7. Качество отображения
- •16.2.8. Панель небезопасных настроек плейера
- •16.3. Дополнительные возможности автономного плейера
- •16.3.1. Проекторы
- •16.3.2. Функция fscommandf()
- •16.4. Взаимодействие между фильмами, проигрываемыми разными плейерами
- •16.4.1. Создание кода отправки данных
- •16.4.2. Создание кода получения данных
- •16.4.3. Пример использования класса LocalConnection
- •16.5. Взаимодействие с браузером
- •16.5.1. Теги <EMBED> и <OBJECT>
- •16.5.2. Передача данных из HTML-окружения при загрузке фильма
- •16.5.3. Решение проблемы кнопок навигации браузера
- •16.5.4. Передача команд браузеру. Функция getURL()
- •16.5.5. Взаимодействие с JavaScript при помощи функции fscommand()
- •16.5.6. Управление SWF-фильмом посредством JavaScript
- •16.5.7. Определение наличия в системе Flash-плейера нужной версии
- •16.6. Взаимодействие со средой разработки
- •16.6.1. Настройка панели Actions
- •16.6.2. Объект CustomActions
- •16.6.3. Взаимодействие с JSFL
- •16.7. Взаимодействие со средствами чтения с экрана
- •16.8. Получение информации об использующемся аппаратном и программном обеспечении
- •16.9. Сохранение данных на диске
- •16.9.1. Создание объектов SharedObject
- •16.9.2. Чтение данных из объектов SharedObject
- •16.9.3. Удаление sol-файлов
- •16.9.4. Серверные объекты SharedObject
- •16.9.5. Решение проблемы выделения цветом посещенных ссылок
- •16.10. Взаимодействие с принтером
- •16.10.1. Функции печати
- •16.10.2. Класс PrintJob
- •Проект 16: Создаем свой инструмент
- •Глава 17. Обмен текстовыми данными с сервером
- •17.1. Принципы сетевой безопасности Flash MX 2004
- •17.1.1. Правила определения идентичности доменов
- •17.1.2. Требование идентичности протоколов
- •17.1.3. Снятие ограничений на доступ к содержимому фильма
- •17.1.4. Снятие ограничений на доступ к внешним данным
- •17.1.5. Преодоление ограничений для сокетов
- •17.1.6. Создание приложений, отвечающих принципам безопасности
- •17.2. Загрузка текстовых данных с сервера
- •17.2.1. Создание файла сданными
- •17.2.2. Функция loadVariables()
- •17.2.3. Класс LoadVars
- •17.3. Взаимодействие с серверным скриптом
- •17.3.1. Запрос с выводом результата в браузере
- •17.3.2. Запрос с отправкой результата в фильм
- •17.3.3. Задание заголовков запроса
- •17.4. Работа с сокетами
- •17.4.1. Класс XMLSocket
- •17.4.2. Создание сокета-сервера
- •17.5. Работа с XML
- •17.5.1. Введение в ХМL
- •17.5.2. Объектная модель XML. DOM
- •17.5.3. Преобразование XML-текста в дерево объектов DOM
- •17.5.4. Обход дерева DOM
- •17.5.5. Создание и модификация XML-документа
- •17.5.6. Обмен XML-данными с сервером
- •Проект 17: Создаем сетевую игру
- •Дополнительные главы
- •Глава 18. Обмен с сервером сложными данными
- •Глава 19. Компоненты
- •Глава 20. Полезные мелочи
сивами — но внешне их поведение весьма схоже с массивами универсальных языков. Поэтому мы, удобства ради, называем их массивами, хотя это, строго говоря, не совсем верно. Аналогично мы будем использовать и понятие «класс», чтобы применяемая нами терминология была близка к традиционной терминологии объектно-ориентированного программирования. Однако нужно помнить, что между классами универсальных языков и конструкторами ActionScript 1.0 имеется много различий. Кстати, поэтому в ЕСМА-262 (третье издание) не используется понятие «класс». Функ- ции-конструкторы называются просто объектами (например, объект Array, но не класс Array), Вообще объектно-ориентированное программирование в ActionScript i .0 повторяет лишь некоторые стороны его многогранности, например, в C++. И это абсолютно оправданно, так как язык сценариев должен быть скорее простым, чем изящным и пластичным, но требующим изрядной подготовки.
В этой книге под классом мы будем понимать множество объектов, созданных одним конструктором.
9.2.5. Наследование
Как было показано выше, при активации функции-конструктора с использованием оператора new происходит создание объекта с последующим заданием его свойств за счет выполнения кода в блоке. При этом каждый экземпляр класса получает индивидуальный набор свойств. Зачастую это не совсем рационально. Так, если значение свойства должно быть одинаковым для всех объектов класса, то создавать отдельную его копию для каждого экземпляра — это не лучший шаг. Гораздо эффективнее сохранить такое свойство в конструкторе, а объектам лишь указать, где оно находится. При этом при необходимости узнать значение свойства все экземпляры класса будут обращаться к одному объектуданных, что может дать весьма ощутимую экономию в потребляемых ресурсах компьютера. Описанная модель, по которой объекты могут использовать методы и свойства других объектов, называется наследованием.
В ActionScript наследование реализуется при помощи прототипов конструкторов. Прототип — это объект, сохраненный в свойстве prototype конструктора. Данное свойство имеется у всех функций, в чем можно убедиться, сняв защиту от перечисления со скрытых свойств:
function func():Void {} ASSetPropFlags{func, null, null, 1); for (var i in func) {
trace(i); // Выводит: prototype __proto__ constructor
Каждый объект имеет ссылку на прототип своего конструктора. Если запрашиваемое свойство не обнаруживается в числе компонентов объекта, проверяется прототип. Если в прототипе обнаруживается свойство, то его значение считывается. В противном случае проверяется прототип надкласса — и так до конца цепочки наследования.
Таким образом, если вы хотите, чтобы объекты класса наследовали свойство или метод, то данные компоненты должны быть сохранены в прототипе конструктора:
function Кот(пол:String, цвет:String, характер:String):Void { // Код, инициализирующий индивидуальные свойства экземпляров this.пол=пол, this.цвет=цвет, this.характер=характер;
}
// Задаем свойства, которые объектами класса должны наследоваться Кот.prototype.лап=4, Кот.prototype.хвост=1, Кот.prototype.нос=1;
var барсик = new Кот("кот", "рыжий", "вредный"); // Создаем экземпляр класса
// Перечисляем все свойства объекта
for (var i in барсик) { |
// Выводит: нос=1 хвост=1 лап=4 |
trace(i+"="+6apсик[i]); |
|
} |
// характер=вредный цвет=рыжий пол=кот |
|
Свойство, наследуемое из прототипа, не может быть изменено или удалено. Это связано с тем, что
если вы попытаетесь присвоить ему новое значение, то интерпретатор, не обнаружив у объекта свойства с таким именем, просто создаст новое свойство:
function Func ():Void{}; Func.prototype.prop="Привет"; var obj=new Func();
obj.рrор="Пока"; |
// |
Пытаемся |
переопределить наследуемое свойство |
|
trace(obj.prop); |
// |
Выводит: |
Пока |
|
trace(Func.prototype.prop); |
// |
Выводит: Привет (значение свойства прототипа |
||
|
|
|
// |
изменено не было) |
Если имена «личного» и наследуемого свойства совпадают, то при обращении будет возвращено значение собственного свойства объекта. Это явление называется переприсваиванием свойств.
Прототип является объектом класса Object. Это означает, что, если свойство не обнаруживается в прототипе класса, интерпретатор обращается к прототипу конструктора Object. Из этого вытекают два важных следствия:
•класс Object всегда завершает цепочку наследования. Следовательно, любой объект наследует методы его прототипа. Исключением является только объект Global, свойством которого является сам конструктор Object();
•по умолчанию цепочка наследования не может быть длиннее двух звеньев (прототип конструктора класса и прототип конструктора Object). Правда, ее можно с легкостью искусственно удлинить. (Как это делается, мы поговорим в следующем подразделе.)
Проверить справедливость приведенных утверждений очень просто:
function Func():Void {} |
// |
Создаем конструктор |
trace(Func.prototype instanceof |
Object); // |
Выводит: true (прототип |
|
// |
принадлежит к классу Object) |
//Делаем доступными для перечисления свойства прототипа конструктора
//Object — так мы сможем проверить факт их наследования
ASSetPropFlags(Object.prototype, null, null, 7);
var obj = new Func(); |
// Создаем экземпляр класса func |
|
for (var i in obj) { |
// Перечисляем все собственные |
|
trace(); |
// Выводит: |
// и наследуемые свойства объекта obj |
toLocaleString isPropertyEnumerable |
||
|
// isPrototypeOf hasOwnProperty |
|
|
// toString valueOf addProperty unwatch watch constructor |
|
|
// (все эти свойства унаследованы от прототипа конструктора Object())) |
Схема, иллюстрирующая наследование для объектов любых встроенных классов (кроме класса XML, у которого есть надкласс XMLNode) и объектов пользовательских классов, у которых искусственно не удлинялась цепочка прототипов, показана на рис. 9.1.

Object.prototype
Constructor.prototype
Constructor
Obj1 Obj2 Obj3
Рис. 9.1. Типичная схема наследования
Объект «знает», где находится прототип его класса, благодаря наличию специального свойства __proto__. Данное свойство хранит ссылку на прототип конструктора, участвовавшего в создании объекта. Свойство __proto__ имеется абсолютно у всех объектов, кроме Global:
function Func():Void{} var obj = new Func();
//__proto__ и остальные служебные свойства защищены от перечисления -
//эту защиту нужно снять
ASSetPropFlags(obj, null, null, 1); for (var i in obj) {
trace(i); // Выводит: constructor __proto__
//(это обязательный минимальный набор свойств для любого объекта)
}
trace(obj.__proto__ == Func.prototype); // Выводит: true (свойство
// __proto__ указывает на прототип класса)
Свойство __proto__ может быть использовано для определения, к какому классу относится объект. Однако практическую важность оно представляет прежде всего потому, что, переопределяя его, можно создавать цепочки наследования любой длины.
Вторым обязательным свойством, имеющимся у любого объекта, является свойство constructor. Данное свойство хранит ссылку на конструктор, при помощи которого был создан объект:
function Func():Void {} var obj = new Func();
trace(obj.constructor Func); // Выводит: true
Свойства __proto__ и constructor задаются при создании объекта, Чтобы понять, как это делается, просмотрите еше раз созданную нами в предыдущем разделе функцию my_new, эмулирующую оператор new.
Интересные особенности связаны с использованием методов и свойств классов String, Boolean, Number. Как вы помните, они могут быть применены по отношению не только к объектам данных классов, но и к величинам соответствующих элементарных типов. Например:
trace("Привет".length); // Выводит: 6
Возникает вопрос: как может наследовать объект данных элементарного типа методы и свойства класса? Ответ — никак. Просто при использовании оператора «.» его левый операнд автоматически преобразуется в объект (аналогичную операцию проводит функция Object). Данное преобразование проводится над копией объекта данных, поэтому оно никак не сказывается на значении переменной, прописанной в качестве левого операнда «.». Доказать справедливость приведенных в
данном абзаце утверждений можно, определив тип величины, соответствующей свойству this объекта активации метода, вызванного объектом данных элементарного типа:
String.prototype.method = function() { trace(typeof this);
};
par="Привет"; // Переменная, хранящая элементарную строку par.method(); // Выводит: object (строка была преобразована в объект)
Сделаем краткое резюме. Итак, у объекта может быть два вида свойств. Свойства могут принадлежать ему непосредственно. Обычно такие свойства инициализируются при выполнении кода конструктора, и в них хранятся данные, которые должны быть индивидуальны для каждого объекта. Второй вид свойств — это наследуемые свойства. Они сохраняются в прототипе конструктора, и их совместно используют все экземпляры класса. В таких свойствах сохраняют методы и свойства, значения которых должны быть одинаковы для всех объектов. По умолчанию прототип является объектом класса Object, поэтому методы прототипа конструктора Object наследуются абсолютно всеми объектами ActionScript. Непосредственно механизм наследования реализуется при помощи особых скрытых свойств __proto__(указывает на прототип конструктора объекта) и constructor (указывает на конструктор объекта).
9.2.6. Создание надклассов и подклассов
По умолчанию длина цепочки прототипов в ActionScript не может превышать двух звеньев (прототип конструктора объекта и прототип конструктора Object). Этого далеко не всегда достаточно. Очень часто бывает необходимым организовывать более сложное наследование, создавая подклассы и надклассы.
Класс А называется надклассом по отношению к некоторому классу В, если объектами В наследуются методы и свойства класса А. Соответственно класс В в этом случае является подклассом класса А. Чтобы сделать класс А надклассом В, достаточно изменить значения свойств__proto__и (не обязательно) constructor прототипа конструктора класса В. Свойство__proto__должно указывать на прототип надкласса, constructor — на его конструктор.
Возвратившись к выбранной в самом начале главы ассоциации объекта с котом, можно, зная способ удлинения цепочки прототипов, несколько улучшить схему наследования для класса Кот. Сделать это можно, создав надкласс Млекопитающие, прототип конструктора которого будет хранить общие для всех теплокровных животных свойства (число лап, ушей, хвостов и т. д.):
function Млекопитающие():Void {}
//Создаем конструктор надкласса
//Задаем общие для всех млекопитающих свойства Млекопитающие.prototype.лап=4;
Млекопитающие.prototype.xвocт=1;
Млекопитающие.prototype.нос=1;
function Кот(пол:String, цвет:String, характер:String) {
// Задаем индивидуальные свойства кота
this.пoл=пол, this.цвет=цвет, this.характер=характер; }
//Делаем класс Млекопитающие надклассом класса Кот Кот.prototype.__proto__ = Млекопитающие.prototype;
Кот.prototype.constructor = Млекопитающие; // Данное предложение
//не обязательно
//Создаем экземпляр класса Кот
var барсик = new Кот("кот", "рыжий", "вредный");
for (var i in барсик) { // Перечисляем свойства экземпляра trace(i + "="+6apcик[i]); // Выводит:
//нос=1 хвост=1 лап=4 (унаследованы от надкласса)
//характер=вредный цвет=рыжий пол=кот
Вне зависимости от того, насколько сложной является цепочка наследования для объекта, ее последним звеном всегда будет прототип конструктора Object. Это связано с тем, что свойство__proto__прототипа любого конструктора по умолчанию указывает на Object.prototype. Создать
же собственный надкласс для всех классов в цепочке наследования, естественно, невозможно, так как при этом она станет бесконечной.
Изменяя значения свойств __proto__ и constructor, можно объекты, изначально принадлежащие к одному классу, делать экземплярами другого. Используя этот ход, можно, например, выделить в подкласс группу клипов. Это позволит оперировать сразу всей группой, не влияя на остальные клипы в фильме. Вспомните проект, в котором мы собирали из кубиков большой куб. Тогда, чтобы при щелчке по кубику он исчезал, мы воспользовались событием onPress. Чтобы не создавать для каждого экземпляра отдельный обработчик, соответствующий метод мы сохранили в прототипе класса MovieClip. При этом он был унаследован всеми кубиками. Однако подобное решение было приемлемо лишь потому, что на поле никаких клипов, кроме кубиков, не было. Иначе при щелчке исчезали бы даже те клипы, которые, по идее, этого делать не должны. Чтобы этого не происходило, кубики следует выделить в подкласс класса MovieClip, сохранив обработчик события onPress в его прототипе.
Переписывать проект мы не будем. Вместо этого решим схожую по идее, но более простую задачу:
// Создайте клип в виде кружочка и назовите его bl
function Ball():Void {} // Класс, к которому будут относиться шарики
//Делаем класс Ball подклассом класса MovieClip Ball.prototype.constructor = MovieClip; Ball.prototype.__proto__ = MovieClip.prototype;
//Создаем 100 случайно распределенных кружков for (var i = 0; i<100; i++) {
bl.duplicateMovieClip("bl"+i, i, {_x:Math.random()*550, _y:Math.random()*450});
//Делаем полученный экземпляр объектом класса Ball this["bl"+i].__proto__ = Ball.prototype;
this["bl"+i].constructor = Ball; // Данное предложение не обязательно
}
//При щелчке по кружку он должен исчезнуть
Ball.prototype.onPress = function():Void { this.removeMovieClip();
};
Приведенный пример демонстрирует очень интересную особенность реализации наследования в ActionScript. Чтобы объект принадлежал к некоторому классу, совсем не обязательно, чтобы он был создан при помощи его конструктора. Для этого достаточно, чтобы его свойство__proto__хранило указатель на прототип нужного конструктора.
Вообще же утверждение о принадлежности объекта к какому-то классу не очень корректно в случае ActionScript 1.0. Так, объект может быть создан одним конструктором, а получать свойства из прототипа другого. Правильнее говорить, что объект наследует свойства некоторых классов. Именно поэтому оператор instanceof определяет не то, указывает ли его правый операнд на тот же конструктор, что и свойство constructor объекта, заданного в качестве левого операнда, а имеется ли прототип данного конструктора в цепочке наследования объекта.
Из-за того, что сложное наследование реализуется в ActionScript 1.0 весьма искусственно путем переопределения свойства __proto__объектов и конструкторов, вполне вероятна такая ситуация, когда надкласс будет ссылаться на прототип подкласса. Это будет означать, что цепочка наследования станет замкнутой и поиск свойства в ней может продолжаться бесконечно долго. Чтобы этого не происходило, в ActionScript длина цепочки прототипов ограничена 256 звеньями. Если этот лимит окажется превышенным, то работа кода будет остановлена и на экран будет выведено со-
общение: 256 levels of prototype chain were exceeded. This is probably a circular prototype chainFurther execution of actions has been disabled in this movie. (256 уровней цепочки прототипов были превышены. Эта цепочка прототипов, вероятно, зациклена. Дальнейшее выполнение кода в этом фильме было прекращено).
Пример зацикленной цепочки наследования: