Про то еще типы

 

[письмо]

Спасибо за Вашу статью по движению, как всегда очень все понятно. Я так обнаглел, что решил еще попросить - не могли бы Вы мне доступным языком объяснить, что такое прототипы и, главное, для чего они? Во многих исходниках их встречаю, но что-то никак не могу разложить в голове по полочкам :) Спасибо заранее!

[/письмо]

 

Эээх! прототипы! Про то еще типы. Действительно с непривычки голову можно сломать. Особенно радует, что объясняют про них как правило оч мудрёно. Что-ж, попробуем иначе.

 

Все мы знаем что такое мувик. У всех мувиков есть функции и методы, например: gotoAndPlay(), а так-же свойства, например _xscale. А еще мувики могут хранить в себе переменные и пользовательские функции. И это понятно.

Но бывают ситуации, когда необходимо, чтобы все мувики имели некую пользовательскую функцию.

В руте в новом FLA, в первом и единственном кадре пишем:

 

function myTrace() { // задаем функцию

trace(this); // просим вывести в окно output сыылку на мувик

}

this.myTrace() // вызываем функцию

 

и действиельно, например такая, не очень мудреная функция может понадобиться в процессе отладки. Но если создать мувик (создайте и обзовите экземпляр на сцене как-нибудь, я его назвал mc, но можно и dj (хе-хе) ) и в этом мувике написать:

 

onClipEvent (load) {

this.myTrace()

}

 

то помимо самого первого трейса ничего не будет. Потому как нету в этом мувике такой функции. Дык что теперь, чтобы вызвать функцию каждый раз ее прописывать надо?

- вот тут-то и пригодятся страшные и ужасные прототипы.

заменим в руте определение функции на:

 

MovieClip.prototype.myTrace = function () { // задаем функцию в прототипе мувиклипа

trace(this); // просим вывести в окно output сыылку на мувик

}

this.myTrace() // вызываем функцию

 

тестанем Ctrl+Enter.

Ух-ты, мувик mc (он-же dj (хе-хе)) отозвался!!. Если вы случайно не удалили вызов myTrace в нем %).

Теперь стоит пойти попить чаю (совет для некурящих).

 

Это что-же получается?

Мы в мувике функцию не задавали, а она там есть! Но нет. на самом деле ее там нет. Функция теперь лежит у нас в прототипе мувиклипа. Опа. А что же произошло?

- мувик mc порылся у себя, и не нашел этой функции. Но на этом его поиски не закончились!!! Мувик полез в поискать в чёрный ящик своего класса (класс у мувика - MovieClip), который называется прототип. И этот черный ящичек имеестя у всех объектов, а не только у мувиклипов.

Вывод первый: если что-нибудь положить в прототип мувиклипа, то это должно найтись без дополнительных усилий с нашей стороны. Нужно просто позвать, мувик сам найдет. И не только мувик, но и любой объект.

 

Object, Array, String, Number.... продолжите список сами. У них у всех есть черный ящичек по имени прототип. И мы уже обнаружили первое свойство прототипа. Он доступен всем объектам класса и его легко использовать.

 

Доступен всем объектам класса.... меня понесло, извините. Попросту говоря, если мы пихаем функцию, свойство или переменную в прототип мувиклипа, то найти это может мувиклип. Массив не найдет. И xml объект тоже не найдет.

 

А что произойдет, если такая функция, свойство или переменная уже имеется у мувика? Помотрим:

в мувике добавим определение функции:

 

onClipEvent (load) { // при загрузке

function myTrace (){ // задаем функцию

trace(this+" is busy") // вывода сообщения линк на мувик+" is busy"

}

this.myTrace() // и вызываем функцию

}

 

и что мы видим?

Мы видим вывод второй: как только мувик находит, нужную функцию, то тут же перестает искать дальше. Поскольку ищет мувик всегда вначале у себя, и если функция с таким именем уже есть просто не добирается до прототипа.

 

А если нам нужна функция, которую бы могли видеть все объекты, а не только мувики? И это возможно. Дело в том, что все объекты являются дочерними объектами класса Object, простите, меня опять понесло...

У людей есть Адам, сиречь пра-прародитель. У объектов во флеше тоже есть свой пра-прародитель. Имя ему Object. И от него произошли все объекты. И наследовали объекты от него все его умения. И также, как и наш незабвенный mc в случае, если не могут найти у себя функцию, свойство или переменную, ищут ее у своего родителя - у Object.

Поэкспериментим чуток, заменим месторасположение функции, поместим ее в Object:

 

Object.prototype.myTrace = function () { // задаем функцию в прототипе мувиклипа

trace("> "+ this+" is " + typeof this +" called from Object prototype"); // сделаем информативней наш трейс ([объект] это [тип объекта] вызван из прототипа Object)

}

this.myTrace() // вызываем функцию

 

видимый результат не изменился. Но теперь эту функцию можно вызывать откуда угодно, попробуем вызвать ее из массива и XML, ниже допишем:

this.myArray=[1, 2, 3] // создаем массив со значениями 1, 2, 3

this.myArray.myTrace() // вызываем из массива наш трейс

this.myXML = new XML ("<xml><item>Hello world</item></xml>")// создаем новый XML

this.myXML.myTrace()// вызываем из него наш трейс

 

ага, вот вот... параллельно понимаем, что такое this :o)

Итак, и xml и массив нашли наш трейс. Как это произошло? Последовательность такая:

1) поискали у себя - не нашли, ищем дальше

2) поискали в прототипе класса (myArray в Array.prototype, а myXML в XML.prototype) - не нашли, ищем дальше

3) поискали в классе - не нашли, ищем дальше

4) раз нет в нашем классе, то может в родительском классе есть? ищем в прототипе родительского класса: бинго!

 

это похоже на простую жизненную ситуацию:

- а нет ли у тебя какой-нибудь фигни, например, клюшки для гольфа?

ищем так:

у меня нет

у родителей в прихожей нет

у родителей в доме нет

а у дедушки оказалась в прихожей!

 

в поисках мы последовательно обследуем прототипы затем сами классы всё выше и выше забираясь по генеалогическому древу. До Адама, то-есть до Object.

Вывод третий: чем выше в иерархии классов помещаем функцию, тем большему количеству классов она доступна и наоборот.

 

О какой иерархии может идти речь, если все стандартные флешовые объекты являются детьми Object? Дело в том, что вы можете создавать свои классы, которые будут являться наследниками стандартных, а так-же пользовательских классов. А если проще сказать, вы можете наделать детей любому классу, а детям еще детей и так далее. И ветвистое генеалогическое дерево станет реальностью.

 

Идем дальше, пишем скрипт в новом FLA

 

Object.prototype.old_trace = trace // сохраним trace в old_trace

Object.prototype.trace = function() { // перезададим стандартный трейс в Object

old_trace("Object trace"); // вывод в output сообщения

};

Array.prototype.trace = function() { // перезададим стандартный трейс в Array

old_trace("Array trace"); // вывод в output сообщения

};

XML.prototype.trace = function() { // перезададим стандартный трейс в XML

old_trace("XML trace"); // вывод в output сообщения

};

this.myArray = [1, 2, 3]; // создадим массив

this.myXML = new XML ("<xml><item>Hello world</item></xml>") // создадим XML

// вызовем трейс из разных объектов:

this.myArray.trace(); // из массива

this.myXML.trace() // из XML

this.trace(); // из рута (он мувиклип, это я на всякий случай напоминаю)

 

Уффф...

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

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

 

Подробнее:

В нашем примере у объекта XML к моменту вызова функции trace в иерархии находится 3 функции с именем trace: одна в прототипе XML, другая в прототипе Object, третья в самом Object. Реально срабатывает только одна - та, которая ближе всего в иерархии.

Попробуйте удалить по очереди функции из скрипта, каждый раз тестируя результат.

 

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

Если всё еще интересно, и хочется узнать побольше, то настоятельно рекомендую http://www.debreuil.com/docs/, там есть линк на русскую версию, которая пока не работает. Я сейчас пойду в рассылку поругаюсь: еще месяц назад должны были восстановить.

(Прошел месяц, я сходил, поругался, не восстановили. А зип мозно взять здесь)

В крайнем случае, пишите мне на мыло, я вышлю зипом.

 

Применение

 

Это самое простое, во всей этой истории. Того, о чем я сегодня писал хватит на 90% случаев использования прототипов.

Основным их использованием является расширение количества функций.

Что я делаю, когда мне нужно например, разобрать XML по полочкам?

1) http://www.layer51.com/proto

2) захожу на раздел XMLnode

3) копирую свои же функции %)

4) делаю разбор XML, если забываю, как это делается, то захожу к себе на уроки и смотрю "XML - прогулка по дереву" и "Узел XML: применяем атрибуты к мувиклипу"

 

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

вот некоторые линки на библиотеки прототипов.

http://www.layer51.com/proto

http://www.sephiroth.it/download/prototype.php

http://www.five100.com/protos/protoJunkie.html

 

я обычно дальше layer51 не хожу, там удобная навигация, нет никаких картинок всё работает очень шустро и понятно. Для того, чтобы использовать любую из находящихся там функций достаточно посмотреть пример использования, прочитать описание, комментарии, если есть, и все-таки советую потестить скопированную функцию. Свои следы там оставляют не только профессионалы %)

 

Для ознакомления, я полагаю, будет достаточно. пишите на dembicki@narod.ru, задавайте вопросы, предлагайте темы для статей.

 

Hosted by uCoz