Классы

Класс — это абстрактное представление объекта. В классе хранится информация о типах данных, которые может содержать объект, и о его возможных видах поведения. Полезность такой абстракции может быть не такой заметной при создании небольших скриптов, содержащих всего несколько взаимодействующих между собой объектов. Однако по мере увеличения размера программы увеличивается число объектов, которыми необходимо управлять. В этом случае классы позволяют обеспечить оптимальное управление созданием и взаимодействием объектов.

Когда был создан язык ActionScript 1.0, использующие его программисты могли использовать объекты Function для создания конструктов, напоминающих классы. В версии ActionScript 2.0 была добавлена формальная поддержка для классов и введены ключевые слова, такие как class и extends . ActionScript 3.0 не только обеспечивает прежнюю поддержку ключевых слов, представленную в ActionScript 2.0, он также включает новые возможности. Например, ActionScript 3.0 включает усовершенствованное управление доступом с помощью атрибутов protected и internal . Кроме того, обеспечивается более усовершенствованное управление наследованием с помощью ключевых слов final и override .

Для разработчиков, имеющих опыт создания классов на таких языках программирования, как Java, C++ или C#, в ActionScript доступны знакомые функции. В ActionScript используется много аналогичных ключевых слов и имен атрибутов, таких как class , extends и public .

Примечание. В документации Adobe ActionScript термин «свойство» обозначает любой член объекта или класса, включая переменные, константы и методы. Кроме того, несмотря на то, что термины «класс» и «статический член» нередко взаимозаменяются, в этом документе они обозначают разные понятия. Например, в этой главе словосочетание «свойства класса» относится ко всем членам класса, а не только к его статическим членам.

Определения классов

В ActionScript 3.0 в определениях классов используется синтаксис, подобный тому, который использовался для определения классов в ActionScript 2.0. Правильный синтаксис для определения класса вызывает ключевое слово class , за которым следует имя класса. Тело класса, заключенное в фигурные скобки ( {} ), следует за именем класса. Например, следующий код создает класс с именем Shape, содержащий одну переменную visible .

public class Shape 
{ 
    var visible:Boolean = true; 
}

Одно значительное изменение в синтаксисе затрагивает определения классов, находящиеся внутри пакета. В ActionScript 2.0, если класс находится в пакете, имя пакета должно быть включено в объявление класса. В языке ActionScript 3.0, в котором вводится инструкция package , имя пакета должно быть включено в объявление пакета, а не в объявление класса. Например, следующие объявления классов показывают, как класс BitmapData, включенный в пакет flash.display, определяется в ActionScript 2.0 и ActionScript 3.0.

// ActionScript 2.0 
class flash.display.BitmapData {} 
 
// ActionScript 3.0 
package flash.display 
{ 
    public class BitmapData {} 
}

Атрибуты классов

ActionScript 3.0 позволяет изменять определения классов с помощью одного из четырех атрибутов.

Атрибут

Определение

dynamic

Позволяет добавлять свойства для экземпляров во время выполнения.

final

Не должен расширяться другим классом.

internal (по умолчанию)

Видимый для ссылок внутри текущего пакета.

public

Видимый для всех ссылок.

Каждый из этих атрибутов, кроме internal , необходимо явно добавлять для получения соответствующего поведения. Например, если не включить атрибут dynamic в определение класса, то для его экземпляров нельзя будет добавлять свойства во время выполнения. Чтобы присвоить атрибут, необходимо поместить его в начало определения класса, как показано в следующем коде.

dynamic class Shape {}

Обратите внимание, что в список поддерживаемых атрибутов не входит abstract . Абстрактные классы не поддерживаются в ActionScript 3.0. Также обратите внимание на то, что в список не включены атрибуты private и protected . Эти атрибуты имеют значение только внутри определения класса и не могут применяться к самим классам. Если класс не должен открыто отображаться за пределами пакета, поместите его внутрь пакета и пометьте его атрибутом internal . В противном случае можно пропустить атрибуты internal и public , и компилятор автоматически добавит атрибут internal . Можно также определить класс, чтобы он был виден только в исходном файле, в котором он определен. Поместите класс в конец исходного файла ниже закрывающейся фигурной скобки определения пакета.

Тело класса

Тело класса заключается в фигурные скобки. В нем определяются переменные, константы и методы класса. В следующем примере показано объявление класса Accessibility в среде ActionScript 3.0:

public final class Accessibility 
{ 
    public static function get active():Boolean; 
    public static function updateProperties():void; 
}

Также внутри тела класса можно определить пространство имен. В следующем примере показано, как можно определить в теле класса пространство имен и использовать его в качестве атрибута метода этого класса.

public class SampleClass 
{ 
    public namespace sampleNamespace; 
    sampleNamespace function doSomething():void; 
}

ActionScript 3.0 позволяет включать в тело класса не только определения, но и инструкции. Операторы, которые находятся внутри тела класса, но не включены в определение метода, выполняются только один раз. Они выполняются, когда определение класса встречается в первый раз, и создается связанный класс. В следующем примере демонстрируется вызов внешней функции hello() и инструкция trace , которая выводит на экран подтверждение при определении класса.

function hello():String 
{ 
    trace("hola"); 
} 
class SampleClass 
{ 
    hello(); 
    trace("class created"); 
} 
// output when class is created 
hola 
class created

В ActionScript 3.0 можно определить одноименные статическое свойство и свойство экземпляра в одном теле класса. Например, следующий код объявляет статическую переменную с именем message и переменную экземпляра с тем же именем.

class StaticTest 
{ 
    static var message:String = "static variable"; 
    var message:String = "instance variable"; 
} 
// In your script 
var myST:StaticTest = new StaticTest(); 
trace(StaticTest.message); // output: static variable 
trace(myST.message); // output: instance variable

Атрибуты свойств классов

Когда речь идет об объектной модели ActionScript, термин свойство обозначает все, что может быть членом класса, включая переменные, константы и методы. Однако в справочной документации Adobe ActionScript 3.0 для платформы Adobe Flash Platform данный термин используется в более узком смысле. В этом контексте термин «свойство» включает только члены класса, которые являются переменными или определены в методе установки или получения. В ActionScript 3.0 имеется набор атрибутов, которые могут использоваться с любым свойством класса. Эти атрибуты перечислены в следующей таблице.

Атрибут

Определение

internal (по умолчанию)

Видимый для ссылок внутри того же пакета.

private

Видимый для ссылок в том же классе.

protected

Видимый для ссылок в том же классе и в производных классах.

public

Видимый для всех ссылок.

static

Показывает, что свойство принадлежит классу, а не экземплярам класса.

UserDefinedNamespace

Имя пространства имен, определенное пользователем.

Атрибуты пространства имен для управления доступом

ActionScript 3.0 обеспечивает четыре специальных атрибута для управления доступом к свойствам, определенным внутри класса: public , private , protected и internal .

Атрибут public делает свойство видимым во всем сценарии. Например, чтобы сделать метод доступным для кода за пределами пакета, необходимо объявить его с атрибутом public . Это относится ко всем свойствам независимо от того, с использованием каких ключевых слов они объявлены: var , const или function .

Атрибут private делает свойство видимым только для вызывающих методов внутри определяющего класса данного свойства. Это поведение отличает его от атрибута private в ActionScript 2.0, который разрешал подклассу доступ к закрытому свойству суперкласса. Другое значительное изменение поведение имеет отношение к доступу во время выполнения. В ActionScript 2.0 ключевое слово private запрещало доступ только во время компиляции, а во время выполнения этот запрет можно было легко обойти. В ActionScript 3.0 это уже не удастся. Свойства, помеченные атрибутом private , остаются недоступными как во время компиляции, так и во время выполнения.

Например, следующий код создает простой класс с именем PrivateExample с одной закрытой переменной, а затем к этой переменной пытается обратиться внешний метод.

class PrivateExample 
{ 
    private var privVar:String = "private variable"; 
} 
 
var myExample:PrivateExample = new PrivateExample(); 
trace(myExample.privVar);// compile-time error in strict mode 
trace(myExample["privVar"]); // ActionScript 2.0 allows access, but in ActionScript 3.0, this is a run-time error. 

В ActionScript 3.0 попытка обращения к свойству с помощью оператора «точка» ( myExample.privVar ) приведет к ошибке компиляции, если используется строгий режим. В противном случае ошибка появляется во время выполнения, как и в случае использования оператора доступа к свойству ( myExample["privVar"] ).

В следующей таблице подведены результаты попыток обращения к закрытому свойству, которое принадлежит статическому (не динамическому) классу.

Строгий режим

Стандартный режим

оператор «точка» ( . )

ошибка компиляции

ошибка выполнения

оператор «квадратные скобки» ( [] )

ошибка выполнения

ошибка выполнения

В классах, объявленных с использованием атрибута dynamic , попытки обращения к закрытым свойствам не приведут к ошибкам выполнения. Переменная не является видимой, поэтому возвращается значение undefined . Однако ошибка компиляции возникает, если в строгом режиме используется оператор «точка». Следующий пример похож на предыдущий и отличается от него только тем, что класс PrivateExample объявляется с атрибутом dynamic.

dynamic class PrivateExample 
{ 
    private var privVar:String = "private variable"; 
} 
 
var myExample:PrivateExample = new PrivateExample(); 
trace(myExample.privVar);// compile-time error in strict mode 
trace(myExample["privVar"]); // output: undefined

Динамические классы обычно возвращают значение undefined вместо ошибки, когда внешний код пытается обратиться к закрытому свойству класса. В следующей таблице показано, что ошибка выдается, только когда оператор «точка» используется для обращения к закрытому свойству в строгом режиме.

Строгий режим

Стандартный режим

оператор «точка» ( . )

ошибка компиляции

undefined

оператор «квадратные скобки» ( [] )

undefined

undefined

Атрибут protected , впервые введенный в версии ActionScript 3.0, делает свойство видимым для вызывающих методов собственного класса или подкласса. Другими словами, защищенное свойство доступно для собственного класса и подклассов, находящихся под ним в иерархии наследования. Оно доступно даже для подклассов, находящихся в других пакетах.

Для пользователей, знакомых со средой ActionScript 2.0, эта возможность аналогична атрибуту private в среде ActionScript 2.0. Атрибут protected среды ActionScript 3.0 также равнозначен атрибуту protected в Java. Он отличается от атрибута в версии Java тем, что также разрешает доступ к вызывающим объектам в том же пакете. Атрибут protected полезен, когда имеется свойство (переменная или метод), необходимое для подкласса, которое требуется скрыть для кода, находящегося за пределами цепи наследования.

Атрибут internal , впервые введенный в версии ActionScript 3.0, делает свойство видимым для вызывающих методов внутри своего пакета. Это атрибут по умолчанию для кода внутри пакета, он применяется ко всем свойствам, у которых нет ни одного из перечисленных ниже атрибутов:

  • public ;

  • private ;

  • protected ;

  • пространство имен, определенное пользователем.

Атрибут internal похож на управление доступом по умолчанию в Java. Однако в Java нет выраженного имени для этого уровня доступа, и его можно реализовать только путем опущения других модификаторов доступа. Атрибут internal введен в ActionScript 3.0, чтобы можно было выразить намерение сделать свойство доступным только для вызывающих методов в его собственном пакете.

Атрибут static

Атрибут static , который может использоваться со свойствами, объявленными с использованием ключевых слов var , const или function , позволяет присоединить свойство к классу, а не к его экземплярам. Внешний код должен вызывать статические свойства с использованием имени класса, а не экземпляра.

Статические свойства не наследуются подклассами, но входят в цепочку области действия подкласса. Это означает, что в теле подкласса статическое свойство (переменная или метод) может использоваться без ссылки на класс, в котором оно было определено.

Определенные пользователем атрибуты пространства имен

В качестве альтернативы предварительно определенным атрибутам управления доступом можно создать пользовательское пространство имен и использовать его как атрибут. Для одного определения можно использовать только один атрибут пространства имен. Кроме того, нельзя использовать атрибут пространства имен в сочетании с другими атрибутами управления доступом ( public , private , protected , internal ).

Переменные

Переменные могут объявляться с использованием ключевых слов var и const . Для переменных, объявленных с ключевым словом var , значения могут меняться несколько раз во время выполнения сценария. Переменные, объявленные с ключевым словом const , называются константами . Значение присваивается им только один раз. При попытке присвоить новое значение инициализированной константе выдается ошибка.

Статические переменные

Статические переменные объявляются с использованием комбинации ключевого слова static с инструкцией var или const . Статические переменные, присоединяемые к классу, а не к его экземпляру, полезны для хранения и совместного использования информации, которая применяется ко всему классу объектов. Например, статическую переменную уместно использовать, если требуется вести учет количества созданных экземпляров объекта или сохранить максимально допустимое количество экземпляров класса.

В следующем примере создается переменная totalCount для отслеживания количества экземпляров класса и константа MAX_NUM для хранения максимального числа экземпляров. Переменные totalCount и MAX_NUM являются статическими, так как содержат значения, применяемые ко всему классу, а не к отдельному экземпляру.

class StaticVars 
{ 
    public static var totalCount:int = 0; 
    public static const MAX_NUM:uint = 16; 
}

Код, внешний для класса StaticVars и его подклассов, может ссылаться на свойства totalCount и MAX_NUM только через сам класс. Например, выполняется следующий код:

trace(StaticVars.totalCount); // output: 0 
trace(StaticVars.MAX_NUM); // output: 16

К статическим переменным нельзя обратиться через экземпляр класса, поэтому следующий код возвращает ошибки.

var myStaticVars:StaticVars = new StaticVars(); 
trace(myStaticVars.totalCount); // error 
trace(myStaticVars.MAX_NUM); // error

Переменные, объявленные с использованием ключевых слов static и const , должны инициализироваться одновременно с объявлением константы, что и делает класс StaticVars для MAX_NUM . Для константы MAX_NUM нельзя присвоить значение внутри конструктора или метода экземпляра. Следующий код создает ошибку, так как его недопустимо использовать для инициализации статической константы.

// !! Error to initialize static constant this way 
class StaticVars2 
{ 
    public static const UNIQUESORT:uint; 
    function initializeStatic():void 
    { 
        UNIQUESORT = 16; 
    } 
}

Переменные экземпляра

Переменные экземпляра объявляются с использованием ключевых слов var и const , но без ключевого слова static . Переменные экземпляра, присоединяемые к отдельным экземплярам, а не ко всему классу, полезны для хранения значений, присущих экземпляру. Например, класс Array имеет свойство экземпляра с именем length , которое хранит количество элементов массива, содержащееся в определенном экземпляре класса Array.

Переменные экземпляра, объявленные с ключевыми словами var и const , нельзя переопределять в подклассе. Однако для получения функции, подобной переопределению переменных, можно переопределить методы доступа get и set.

Методы

Методы — это функции, которые входят в состав определения класса. Когда создается экземпляр класса, с ним связывается метод. В отличие от функции, объявленной за пределами класса, метод нельзя использовать отдельно от экземпляра, с которым он связан.

Методы определяются с использованием ключевого слова function . Как и любое свойство класса, можно применить любой атрибут свойства класса к методам, включая методы private, protected, public, internal, static или custom namespace. Можно использовать оператор function, аналогичный следующему:

public function sampleFunction():String {}

Также можно использовать переменную, которой присваивается выражение функции, как показано ниже.

public var sampleFunction:Function = function () {}

В большинстве случаев используйте оператор функции, а не выражение, потому что:

  • Инструкции функции более точные и простые для чтения.

  • Инструкции функции позволяют использовать ключевые слова override и final .

  • Операторы функции создают более крепкую связь между идентификатором (именем функции) и кодом в теле метода. Так как значение переменной может быть изменено с помощью инструкции присваивания, связь между переменной и ее выражением функции может в любой момент быть разорвана. Хотя эту проблему можно обойти, объявив переменную с ключевым словом const вместо var , такой прием лучше не использовать, так как он делает код трудным для чтения и не позволяет использовать ключевые слова override и final .

Единственным случаем, когда необходимо использовать именно выражение функции, является присоединение функции к объекту прототипа.

Методы-конструкторы

Методы-конструкторы (иногда их называют просто конструкторами ) представляют собой функции с тем же именем, которым назван класс, в котором они определены. Любой код, включенный в метод-конструктор, выполняется при каждом создании экземпляра класса с использованием ключевого слова new . Например, следующий код определяет простой класс Example, содержащий одно свойство с именем status . Начальное значение переменной status задается в функции конструктора.

class Example 
{ 
    public var status:String; 
    public function Example() 
    { 
        status = "initialized"; 
    } 
} 
 
var myExample:Example = new Example(); 
trace(myExample.status); // output: initialized

Методы-конструкторы могут быть только открытыми, но использование атрибута public является необязательным. Для конструктора нельзя использовать никаких других спецификаторов управления доступом, включая private , protected или internal . Кроме того, с методом-конструктором нельзя использовать пользовательское пространство имен.

Конструктор может явно вызвать конструктор находящегося непосредственно над ним суперкласса с помощью инструкции super() . Если конструктор суперкласса не вызывается явно, компилятор автоматически вставляет вызов перед первой инструкцией в теле конструктора. Также вызывать методы суперкласса можно, используя префикс super в качестве ссылки на суперкласс. Если в теле одного конструктора требуется использовать и конструктор super() , и префикс super , первым должен идти конструктор super() . В противном случае ссылка super может повести себя не так, как предполагалось. Конструктор super() также необходимо вызывать перед инструкциями throw или return .

В следующем примере показано, что происходит при попытке использования ссылки super перед вызовом конструктора super() . Новый класс, ExampleEx, расширяет класс Example. Конструктор ExampleEx пытается получить переменную status, определенную в его суперклассе, но делает это перед вызовом super() . Инструкция trace() в конструкторе ExampleEx возвращает значение null , так как переменная status недоступна, пока не будет вызван конструктор super() .

class ExampleEx extends Example 
{ 
    public function ExampleEx() 
    { 
        trace(super.status); 
        super(); 
    } 
} 
 
var mySample:ExampleEx = new ExampleEx(); // output: null

Хотя в конструкторе можно использовать инструкцию return , он не может вернуть значение. Другими словами, инструкции return не должны иметь связанных выражений или значений. Соответственно, методы-конструкторы не могут возвращать значения, вследствие чего невозможно указать тип возврата.

Если для класса не определить метод-конструктор, компилятор автоматически создает пустой конструктор. Если данный класс расширяет другой, компилятор включает вызов super() в созданный им конструктор.

Статические методы

Статические методы, также называемые методами класса — это методы, которые объявляются с использованием ключевого слова static . Статические методы, присоединяемые к классу, а не к его экземпляру, полезны для инкапсуляции, которая затрагивает не только состояние отдельного экземпляра. Так как статические методы присоединяются ко всему классу, их можно вызвать только через класс, а через его экземпляр — нет.

Статические методы полезны для инкапсуляции, действие которой не ограничивается состоянием экземпляров класса. Другими словами, метод должен быть статическим, если он обеспечивает функцию, которая не оказывает прямого влияния на значение экземпляра класса. Например, класс Date имеет статический метод parse() , который преобразует строку в число. Это статический метод, так как он не оказывает влияния на отдельные экземпляры класса. Вместо этого метод parse() берет строку, которая представляет собой значение даты, анализирует ее и возвращает число в формате, совместимом с внутренним представлением объекта Date. Этот метод не является методом экземпляра, так как его бессмысленно применять к одному экземпляру класса Date.

Сравните статический метод parse() с одним из методов экземпляра класса Date, таким как getMonth() . Метод getMonth() является методом экземпляра, так как он воздействует непосредственно на значение экземпляра, получая определенный компонент (месяц) экземпляра Date.

Так как статические методы не связаны с отдельными экземплярами, в их теле нельзя использовать ключевые слова this и super . Ссылки this и super имеют значение, только в контексте метода экземпляра.

В отличие от других языков программирования на базе классов, в ActionScript 3.0 статические методы не наследуются.

Методы экземпляра

Методами экземпляра являются методы, объявленные без ключевого слова static . Методы экземпляра, присоединяемые к экземплярам, а не ко всему классу, полезны для реализации функций, затрагивающих отдельные экземпляры класса. Например, класс Array содержит метод экземпляра sort() , который воздействует непосредственно на экземпляры Array.

В теле метода экземпляра могут содержаться и статические переменные, и переменные экземпляра. Это означает, что на переменные, определенные в одном классе, можно ссылаться с использованием простого идентификатора. Например, следующий класс, CustomArray, расширяет класс Array. Класс CustomArray определяет статическую переменную arrayCountTotal для отслеживания общего числа экземпляров класса, переменную экземпляра arrayNumber , отслеживающую порядок создания экземпляров, и метод экземпляра getPosition() , возвращающий значения этих переменных.

public class CustomArray extends Array 
{ 
    public static var arrayCountTotal:int = 0; 
    public var arrayNumber:int; 
 
    public function CustomArray() 
    { 
        arrayNumber = ++arrayCountTotal; 
    } 
     
    public function getArrayPosition():String 
    { 
         return ("Array " + arrayNumber + " of " + arrayCountTotal); 
    } 
}

Хотя внешний код класса должен обращаться к статической переменной arrayCountTotal через объект класса с помощью CustomArray.arrayCountTotal , код, находящийся внутри тела метода getPosition() , может ссылаться непосредственно на статическую переменную arrayCountTotal . Это относится даже к статическим переменным суперклассов. Хотя статические свойства не наследуются в ActionScript 3.0, статические свойства суперклассов входят в область действия. Например, класс Array имеет несколько статических переменных, одна из которых является константой с именем DESCENDING . Код, находящийся в подклассе Array, может обращаться к статической константе DESCENDING с помощью простого идентификатора:

public class CustomArray extends Array 
{ 
    public function testStatic():void 
    { 
        trace(DESCENDING); // output: 2 
    } 
}

Значением ссылки this в теле метода экземпляра является ссылка на экземпляр, к которому присоединен метод. Следующий код демонстрирует, как ссылка this указывает на экземпляр, содержащий метод.

class ThisTest 
{ 
    function thisValue():ThisTest 
    { 
        return this; 
    } 
} 
 
var myTest:ThisTest = new ThisTest(); 
trace(myTest.thisValue() == myTest); // output: true

Наследованием методов экземпляров можно управлять с помощью ключевых слов override и final . Атрибут override можно использовать для переопределения унаследованного метода, а атрибут final — для запрета переопределения метода подклассами.

Методы доступа get и set

Методы доступа get и set, также называемые getter и setter , позволяют соблюдать принципы сокрытия информации и инкапсуляции, обеспечивая простой в использовании интерфейс программирования для создаваемых классов. Функции get и set позволяют делать свойства класса закрытыми, но при этом пользователи класса могут обращаться к этим свойствам так, будто они обращаются к переменной класса, а не вызывают метод класса.

Преимущество такого подхода заключается в том, что он позволяет отказаться от традиционных функций методов доступа с громоздкими именами, такими как getPropertyName() и setPropertyName() . Другое преимущество методов get и set состоит в том, что они позволяют избежать создания двух открытых функций для каждого свойства, разрешающего доступ для чтения и записи.

Следующий пример класса GetSet включает методы доступа get и set с именем publicAccess() , которые обеспечивают доступ к закрытой переменной privateProperty .

class GetSet 
{ 
    private var privateProperty:String; 
     
    public function get publicAccess():String 
    { 
        return privateProperty; 
    } 
     
    public function set publicAccess(setValue:String):void 
    { 
        privateProperty = setValue; 
    } 
}

Если обратиться к свойству privateProperty напрямую, возникает ошибка, как показано ниже.

var myGetSet:GetSet = new GetSet(); 
trace(myGetSet.privateProperty); // error occurs

Вместо этого пользователь класса GetSet использует свойство, похожее на свойство publicAccess , но на самом деле являющееся парой функций методов доступа get и set, которые работают с закрытым свойством privateProperty . В следующем примере создается экземпляр класса GetSet, а затем задается значение свойства privateProperty с помощью открытого метода доступа publicAccess .

var myGetSet:GetSet = new GetSet(); 
trace(myGetSet.publicAccess); // output: null 
myGetSet.publicAccess = "hello"; 
trace(myGetSet.publicAccess); // output: hello

Функции get и set также позволяют переопределять свойства, унаследованные от суперкласса, что невозможно выполнить при использовании обычных переменных-членов класса. Переменные-члены класса, объявленные с использованием ключевого слова var , не могут переопределяться в подклассе. Однако это ограничение не распространяется на свойства, созданные с помощью функций get и set. Для функций get и set, унаследованных от суперкласса, можно использовать атрибут override .

Связанные методы

Связанный метод, иногда называемый замыканием метода — это метод, извлеченный из своего экземпляра. К числу связанных методов относятся методы, переданные функции в качестве аргументов или возвращенные функцией в качестве значений. Впервые в ActionScript 3.0 связанный метод уподобляется замыканию функции в том, что он сохраняет всю свою лексическую среду даже при извлечении из экземпляра. Однако между связанным методом и замыканием функции есть важное отличие: ключевое слово this для связанного метода продолжает ссылаться на экземпляр, в котором реализуется метод, то есть остается связанным с ним. Другими словами, ссылка this в связанном методе всегда указывает на исходный объект, в котором определен метод. Для замыканий функций ссылка this является общей, то есть она указывает на любой объект, с которым связана функция в момент вызова.

Важно понимать суть связанных методов, если используется ключевое слово this . Как вы помните, ключевое слово this обеспечивает ссылку на родительский объект метода. Большинство программистов, использующих ActionScript, считают, что ключевое слово this всегда представляет объект или класс, содержащий определение метода. Однако это не всегда так, если не применяется связывание метода. Например, в предыдущих версиях ActionScript ключевое слово this не всегда ссылается на экземпляр, в котором реализован метод. Когда методы извлекаются из экземпляра в ActionScript 2.0, ссылка this не связывается с исходным экземпляром, а переменные и методы экземпляра становятся недоступными. В ActionScript 3.0 этого не происходит, так как при передаче методов в качестве параметра автоматически создаются связанные методы. Связанные методы обеспечивают, чтобы ключевое слово this всегда ссылалось на объект или класс, в котором определяется метод.

Следующий код определяет класс ThisTest, который содержит метод foo() , определяющий связанный метод, и метод bar() , возвращающий связанный метод. Внешний код создает экземпляр класса ThisTest, создает метод bar() и сохраняет возвращенное значение в переменной myFunc .

class ThisTest 
{ 
    private var num:Number = 3; 
    function foo():void // bound method defined 
    { 
        trace("foo's this: " + this); 
        trace("num: " + num); 
    } 
    function bar():Function 
    { 
        return foo; // bound method returned 
    } 
} 
 
var myTest:ThisTest = new ThisTest(); 
var myFunc:Function = myTest.bar(); 
trace(this); // output: [object global] 
myFunc(); 
/* output:  
foo's this: [object ThisTest] 
output: num: 3 */

Две последние строки кода показывают, что ссылка this в связанном методе foo() по-прежнему указывает на экземпляр класса ThisTest, несмотря на то, что ссылка this в предшествующей строке указывает на глобальный объект. Более того, связанный метод, сохраненный в переменной myFunc , сохранил доступ к переменным-членам класса ThisTest. Если выполнить этот же код в ActionScript 2.0, ссылки this будут одинаковыми, а переменная num получит значение undefined .

Добавление связанных методов имеет самое большое значение, когда речь идет об обработчиках событий, так как метод addEventListener() требует, чтобы в качестве аргумента передавалась функция или метод.

Перечисления с классами

Перечисления — это пользовательские типы данных, которые создаются для инкапсуляции небольшого набора значений. Язык ActionScript 3.0 не поддерживает специфическую функцию перечисления, в отличие от языка C++, в котором есть ключевое слово enum , или Java, где предусмотрен интерфейс Enumeration. Однако перечисления можно создавать с помощью классов и статических констант. Например, класс PrintJob в ActionScript 3.0 использует перечисление PrintJobOrientation для хранения значений "landscape" (альбомная) и "portrait" (книжная), как показано в следующем коде:

public final class PrintJobOrientation 
{ 
    public static const LANDSCAPE:String = "landscape"; 
    public static const PORTRAIT:String = "portrait"; 
}

Класс перечисления условно объявляется с использованием атрибута final , так как нет необходимости расширять класс. Класс включает только статические члены, а это означает, что экземпляры класса не создаются. Вместо этого, объект класса обеспечивает прямой доступ к значениям перечисления, как показано в следующем фрагменте кода.

var pj:PrintJob = new PrintJob(); 
if(pj.start()) 
{ 
    if (pj.orientation == PrintJobOrientation.PORTRAIT) 
    { 
        ... 
    } 
    ... 
}

Все классы перечисления в ActionScript 3.0 содержат только переменные типа String, int или uint. Преимущество использования перечислений вместо буквенной строки или числовых значений заключается в том, что в перечислениях проще выявить опечатки. Если имя перечисления введено с ошибкой, компилятор ActionScript выдает ошибку. При использовании строк компилятор не сообщает о неправильном написании слова или числа. В предыдущем примере компилятор выдает ошибку, если введено неправильное имя для константы перечисления, как показано в следующем фрагменте.

    if (pj.orientation == PrintJobOrientation.PORTRAI) // compiler error

Однако компилятор не выдает ошибку, если неправильно введено строковое значение, как показано ниже.

    if (pj.orientation == "portrai") // no compiler error

Второй метод создания перечислений также подразумевает создание отдельного класса со статическими свойствами для перечисления. Однако этот метод отличается тем, что каждое из статических свойств, содержит экземпляр класса вместо строки или целого числа. Например, следующий код создает класс перечисления для дней недели.

public final class Day 
{ 
    public static const MONDAY:Day = new Day(); 
    public static const TUESDAY:Day = new Day(); 
    public static const WEDNESDAY:Day = new Day(); 
    public static const THURSDAY:Day = new Day(); 
    public static const FRIDAY:Day = new Day(); 
    public static const SATURDAY:Day = new Day(); 
    public static const SUNDAY:Day = new Day(); 
}

Этот метод не используется в ActionScript 3.0, но используется многими разработчиками, которые предпочитают его улучшенную проверку написания. Например, метод, возвращающий значение перечисления, может ограничить возвращаемое значение определенным типом данных перечисления. Следующий код демонстрирует функцию, возвращающую день недели, а также вызов функции, использующий тип перечисления в качестве аннотации типа.

function getDay():Day 
{ 
    var date:Date = new Date(); 
    var retDay:Day; 
    switch (date.day) 
    { 
        case 0: 
            retDay = Day.MONDAY; 
            break; 
        case 1: 
            retDay = Day.TUESDAY; 
            break; 
        case 2: 
            retDay = Day.WEDNESDAY; 
            break; 
        case 3: 
            retDay = Day.THURSDAY; 
            break; 
        case 4: 
            retDay = Day.FRIDAY; 
            break; 
        case 5: 
            retDay = Day.SATURDAY; 
            break; 
        case 6: 
            retDay = Day.SUNDAY; 
            break; 
    } 
    return retDay; 
} 
 
var dayOfWeek:Day = getDay();

Кроме того, класс Day можно расширить, чтобы он связывал целое число с каждым днем недели и определял метод toString() , возвращающий строковое представление дня.

Классы встроенных ресурсов

В языке ActionScript 3.0 используются особые классы для представления встроенных ресурсов, называемые классами встроенных ресурсов . Встроенный ресурс — это ресурс, такой как звук, изображение или шрифт, включенный в SWF-файл во время компиляции. Встраивание ресурса вместо его динамической загрузки гарантирует его доступность во время выполнения, однако за счет увеличения размера SWF-файла.

Использование классов встроенных ресурсов в инструменте Flash Professional

Чтобы встроить ресурс, сначала поместите его в библиотеку FLA-файла. Затем используйте свойство связывания ресурса, чтобы передать имя для его класса встроенных ресурсов. Если класса с таким именем нет в пути к классам, он создается автоматически. После этого можно создать экземпляр класса встроенных ресурсов и использовать любые определенные или унаследованные им свойства и методы. Например, следующий код можно использовать для воспроизведения встроенного звука, связанного с классом встроенных ресурсов PianoMusic.

var piano:PianoMusic = new PianoMusic(); 
var sndChannel:SoundChannel = piano.play();

В противном случае можно использовать тег метаданных [Embed] для встраивания ресурсов в проект Flash Professional, как описано далее. Если в коде используется тег метаданных [Embed] , в инструменте Flash Professional для компиляции проекта используется компилятор Flex, а не компилятор Flash Professional.

Использование классов встроенных ресурсов с помощью компилятора Flex

При компиляции кода с помощью компилятора Flex для встраивания ресурса в код ActionScript используйте тег метаданных [Embed] . Поместите ресурс в основной исходной папке или в другой папке, включенной в путь сборки проекта. Когда компилятор Flex обнаружит тег метаданных Embed, он создаст класс встроенных ресурсов. Обратиться к классу можно через переменную типа данных Class, объявленную сразу после тега метаданных [Embed] . Например, следующий код встраивает звук с именем sound1.mp3 и использует переменную soundCls для хранения ссылки на класс встроенных ресурсов, связанный с этим звуком. После этого создается экземпляр класса встроенных ресурсов, для которого вызывается метод play() .

package 
{ 
    import flash.display.Sprite; 
    import flash.media.SoundChannel; 
    import mx.core.SoundAsset; 
 
    public class SoundAssetExample extends Sprite 
    { 
        [Embed(source="sound1.mp3")] 
        public var soundCls:Class; 
         
        public function SoundAssetExample() 
        { 
            var mySound:SoundAsset = new soundCls() as SoundAsset; 
            var sndChannel:SoundChannel = mySound.play(); 
        } 
    } 
}

Adobe Flash Builder

Чтобы использовать тег метаданных [Embed] в проекте Flash Builder ActionScript, импортируйте все необходимые классы из среды Flex. Например, чтобы встроить звуки, импортируйте класс mx.core.SoundAsset. Чтобы использовать систему Flex, включите файл framework.swc в путь сборки ActionScript. Это приводит к увеличению размера SWF-файла.

Adobe Flex

В противном случае в среде Flex ресурс можно встроить с помощью директивы @Embed() в определении тега MXML.