Показать сообщение отдельно
Старый 29.11.2010, 18:21
Aquahawk вне форума Посмотреть профиль Отправить личное сообщение для Aquahawk Посетить домашнюю страницу Aquahawk Найти все сообщения от Aquahawk
  № 1  
Ответить с цитированием
Aquahawk
 
Аватар для Aquahawk

Регистрация: Nov 2010
Адрес: Москва
Сообщений: 915
Записей в блоге: 4
Отправить сообщение для Aquahawk с помощью ICQ Отправить сообщение для Aquahawk с помощью Skype™
По умолчанию сохранение и последующий вызов функции.

Начну с того что пишу на 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 получили правильные параметры. Почему такие результаты трейса в упор не могу понять.


Последний раз редактировалось iNils; 29.11.2010 в 18:49.