Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   сохранение и последующий вызов функции. (http://www.flasher.ru/forum/showthread.php?t=147231)

Aquahawk 29.11.2010 18:21

сохранение и последующий вызов функции.
 
Начну с того что пишу на flash платформе недавно, ранее 5 лет писал на C/C++ там такого нельзя делать было в принципе, а в as3 можно, но я не до конца понимаю механизм. Что происходит когда мы запоминаем метод объекта? Прочитал вики по ECMAScript и хелп эдоба на эту тему. Стало понятно что функция сама является объектом, и где-то внутри хранит "владельца" т.е. того объекта для которого её вызвали. Т.е. когда мы делаем:
Код AS3:

var qqq:Function = test1.a1;
var www:Function = test2.a1;

то получаем два разных экземпляра функций которые обрабатывают разный объект(test1 и test2 соответственно). Указатель на this хранится где-то внутри этого объекта функции? Также эдоб говорит что этим this можно управлять при вызове функции посредством call() и apply(), однако у мня не получилось, может кто пояснить почему так происходит? Внутри вызываемых функций прописывать this.a += пробовал, ничего не меняется. Варнингов/ошибок нет, функция всё-равно отрабатывает для того объекта от которого была взята.
Код AS3:

package test {
        import flash.display.Sprite;
        public class abra extends Sprite {
                private var test1:testClass;
                private var test2:testClass;
 
                public function abra():void {
                        test1 = new testClass();
                        test2 = new testClass();
 
                        var qqq:Function = test1.a1;
                        var www:Function = test2.a1;
                        var qwe:Function = test2.a2;
 
                        trace("test1.a = " + test1.a + "; test2.a = " + test2.a);
                        qqq();
                        trace("test1.a = " + test1.a + "; test2.a = " + test2.a);
                        www();
                        trace("test1.a = " + test1.a + "; test2.a = " + test2.a);
                        qwe();
                        trace("test1.a = " + test1.a + "; test2.a = " + test2.a);
                        qqq.call(test2);
                        trace("test1.a = " + test1.a + "; test2.a = " + test2.a);
                        qqq.apply(test2);
                        trace("test1.a = " + test1.a + "; test2.a = " + test2.a);
                }
        }
}
class testClass {
        public var a:uint = 0;
 
        public function testClass() {
        }
 
        public function a1():void {
                a += 1;
        }
        public function a2():void {
                a += 2;
        }
}

результат трейса
Код:

test1.a = 0; test2.a = 0
test1.a = 1; test2.a = 0
test1.a = 1; test2.a = 1
test1.a = 1; test2.a = 3
test1.a = 2; test2.a = 3
test1.a = 3; test2.a = 3

При дизассемблировании(swfdump -D) релизной(релиз чтоб листинг чище был) сборки это выглядит так(позволил себе прокомментировать что сразу понятнее было):
Код AS3:

00000) + 0:0 getlocal_0
00001) + 1:0 pushscope
 
/* super(); */
00002) + 0:1 getlocal_0
00003) + 1:1 constructsuper 0 params
 
/* test1 = new testClass(); */
00004) + 0:1 getlocal_0
00005) + 1:1 findpropstrict <q>[private]NULL::testClass
00006) + 2:1 constructprop <q>[private]NULL::testClass, 0 params
00007) + 2:1 initproperty <q>[private]NULL::test1
 
/* test2 = new testClass(); */
00008) + 0:1 getlocal_0
00009) + 1:1 findpropstrict <q>[private]NULL::testClass
00010) + 2:1 constructprop <q>[private]NULL::testClass, 0 params
00011) + 2:1 initproperty <q>[private]NULL::test2
 
/* var qqq:Function = test1.a1; */
00012) + 0:1 getlocal_0
00013) + 1:1 getproperty <q>[private]NULL::test1
00014) + 1:1 getproperty <q>[public]::a1
00015) + 1:1 coerce <q>[public]::Function
00016) + 1:1 setlocal_1
 
/* var www:Function = test2.a1; */
00017) + 0:1 getlocal_0
00018) + 1:1 getproperty <q>[private]NULL::test2
00019) + 1:1 getproperty <q>[public]::a1
00020) + 1:1 coerce <q>[public]::Function
00021) + 1:1 setlocal_2
 
/* var qwe:Function = test2.a2; */
00022) + 0:1 getlocal_0
00023) + 1:1 getproperty <q>[private]NULL::test2
00024) + 1:1 getproperty <q>[public]::a2
00025) + 1:1 coerce <q>[public]::Function
00026) + 1:1 setlocal_3
 
/* qqq(); */
00027) + 0:1 getlocal_1
00028) + 1:1 getglobalscope
00029) + 2:1 call 0 params
00030) + 1:1 pop
 
/* www(); */
00031) + 0:1 getlocal_2
00032) + 1:1 getglobalscope
00033) + 2:1 call 0 params
00034) + 1:1 pop
 
/*qwe();*/
00035) + 0:1 getlocal_3
00036) + 1:1 getglobalscope
00037) + 2:1 call 0 params
00038) + 1:1 pop
 
/* qqq.call(test2); */
00039) + 0:1 getlocal_1 // сложили в стек qqq
00040) + 1:1 getlocal_0 // сложили в стек себя
00041) + 2:1 getproperty <q>[private]NULL::test2 // поискали в себе test2, соответственно на макушке стека теперь не указатель на нас а указатель на test2
00042) + 2:1 callpropvoid <q>[namespace]http://adobe.com/AS3/2006/builtin::call, 1 params // вызвали call, он как и constructSuper ест на один параметр больше чем указанное количество параметров, т.е. он захавает test2 и qqq что лежали на верхушке стека.
 
/* qqq.apply(test2); */
00043) + 0:1 getlocal_1 // тут всё абсолютно аналогично, дублировать не стал.
00044) + 1:1 getlocal_0
00045) + 2:1 getproperty <q>[private]NULL::test2
00046) + 2:1 callpropvoid <q>[namespace]http://adobe.com/AS3/2006/builtin::apply, 1 params

Собственно ничего неожиданного на уровне abc байткода, обычным образом засавали функцию и потом обычным образом вызвали. call и apply получили правильные параметры. Почему такие результаты трейса в упор не могу понять.

alatar 29.11.2010 19:03

Цитата:

то получаем два разных экземпляра функций которые обрабатывают разный объект(test1 и test2 соответственно).
Нет, вы получаете ссылки именно на две функции. Уже без привязки к объектам к которым они изначально относились. Функция это тоже объект.
В данном случае this будет ссылаться на класс в котором будут вызваны эти функции.

Добавлено через 10 минут
Хотя возможно я перепутал с Java. Сейчас проверю.

Aquahawk 29.11.2010 19:14

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

alatar 29.11.2010 19:20

Разница все таки есть.
Цитата:

Методы класса немного отличаются от объектов Function. В отличие от обычного объекта функции метод тесно связан со связанным объектом класса. Поэтому метод или свойство имеют определение, используемое всеми экземплярами одного и того же класса. Из экземпляра можно извлечь методы, обрабатываемые как «связанные» методы (сохраняющие ссылку на исходный экземпляр). В рамках связанного метода ключевое слово this указывает на исходный объект, реализовавший этот метод. В случае функции this указывает на связанный объект на момент вызова функции.
Добавлено через 3 минуты
Если хотите создать именно функцию, то это делается несколько иначе:
Код AS3:

var foo:Function = function():String { return "i just function" }


Aquahawk 29.11.2010 19:29

Слепой, только что читал но не увидел. Ладно, пусть официально указано что метод хранит указатель на свой объект, на то и похоже. Но мы же сохраняем в переменную типа Function и в abc коде происходит приведение типа: coerce <q>[public]::Function. И почему не работает call() и apply() тоже в упор не понятно.

alatar 29.11.2010 19:35

Цитата:

Но мы же сохраняем в переменную типа Function
При чем здесь тип? Если попробуете поставить другой, получите ошибку. Методы имеют тип Function.
Цитата:

И почему не работает call() и apply() тоже в упор не понятно.
Они работают. Причем так, как написано в хелпе.

Aquahawk 29.11.2010 19:38

qqq.call(test2); игнорирует указанный test2 и инкрементирует a содержащуюся в test1, хотя написано что он проигнорирует свой this и заменит его на пришедший в качестве параметра.

alatar 29.11.2010 19:41

Где это написано? Написано как раз противоположное.
Создайте именно функцию (не метод) и все встанет на свои места.

Добавлено через 1 минуту
Цитата:

В рамках связанного метода ключевое слово this указывает на исходный объект, реализовавший этот метод.
Это ваш случай.
Цитата:

В случае функции this указывает на связанный объект на момент вызова функции.
А это относится к функциям, а не к методам.

Aquahawk 29.11.2010 19:53

Цитата:

В некоторых ситуациях может потребоваться, чтобы thisObject указывал на другой объект (например, если функцию необходимо вызвать как метод объекта, но на самом деле она не сохраняется как метод этого объекта):
myObject.myMethod.call(myOtherObject, 1, 2, 3);
Собственно такого поведения и жду.

alatar 29.11.2010 19:58

В данном примере myMethod это свойство (типа Function) класса, к которому относится экземпляр myObject, которое содержит анонимную функцию.


Часовой пояс GMT +4, время: 20:05.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.