Опубликован: 23.12.2005 | Уровень: специалист | Доступ: платный | ВУЗ: Московский физико-технический институт
Лекция 7:

Наследование во Flash MX

Эмуляция with в функциях

Сейчас мы видели, что контекст вызова функции - это объект, не являющийся экземпляром какого-либо класса. Об этом говорит отсутствие ссылки __proto__. То есть у объекта нет прототипа и поля у него заведены только те, что нужны в данном конкретном случае. (Можно, конечно вспомнить про повторяющиеся, хоть и скрытые, поля arguments и this. Но факт остается фактом - эти поля тоже берутся не из прототипа, а заводятся каждый раз заново.) Однако мы уже знаем, что при наследовании в стиле rebel можно "прицепить" базовые классы потом, уже после создания уникальных полей. Для этого всего лишь надо установить ссылку __proto__. Возникает соблазн проделать то же самое и с контекстом вызова. В результате поля того объекта, на который будет указывать __proto__, будут восприниматься так же, как собственные поля контекста вызова. То есть ... как локальные переменные! Это настолько неожиданный вывод, что хочется немедленно его проверить.

_global.dumpObj = function(obj){
		// Снимаем "защиту" со скрытых полей
	ASSetPropFlags(obj,null,0,1);
	for(name in obj){
		trace(name + ": " + obj[name]);	
	}
}
o1 = {k:10, l:20};
var f = function(){
	var x = 5;
	var y = "Текстовая локальная переменная";
	var o2 = {k:15, l:25};	
	
	var getActivation = function(){
		return this;
	}
	
	var act = getActivation();
	act.__proto__ = o1; // Или var.__proto__ = o1;
	
	trace("===================");
	trace("k = " + k);
	trace("l = " + l);
	trace("===================");
		
	k = 145;
	var l = 1111;
		
	trace("===================");
	trace("k = " + k);
	trace("l = " + l);
	trace("===================");
	return getActivation();
}

trace("==== Контекст вызова f ====");
dumpObj(f(1000, [1, 2, 3]));
trace("===========================");
trace("");
trace("******* o1 ********");
dumpObj(o1);
trace("*******************");
trace("");
trace(":::::::: _level0 ::::::::");
dumpObj(this);
trace("::::::::::::::::::::::::::");

На выходе получаем:

==== Контекст вызова f ====
===================
k = 10
l = 20
===================
===================
k = 10
l = 1111
===================
k: 10
l: 1111
__proto__: [object Object]
act: [object Object]
getActivation: [type Function]
o2: [object Object]
y: Текстовая локальная переменная
x: 5
arguments: 1000,1,2,3
this: _level0
===========================
******* o1 ********
k: 10
l: 20
__proto__: [object Object]
constructor: [type Function]
*******************
:::::::: _level0 ::::::::
name: name
__proto__: [object Object]
constructor: [type Function]
k: 145
f: [type Function]
o1: [object Object]
$appPath: file:///K|/Program%20Files/Macromedia/Flash%20MX/
$version: WIN 6,0,21,0
::::::::::::::::::::::::::

Мы видим удивительные (хотя и ожидавшиеся нами) вещи! Действительно, переменные k и l воспринимаются внутри функции (после того, как контексту указали __proto__ ) как локальные! Но более того, они еще и являются чем-то вроде константных локальных переменных! Наша попытка изменить переменную k привела к тому, что была заведена соответствующая переменная в _level0. (Поскольку содержимое объекта, на который указывает __proto__, не меняется, то должна быть заведена новая переменная; но поскольку ключевое слово var не было применено, то переменная заводится в объекте, из которого была вызвана функция f.) Поскольку приоритет в функции имеет локальная переменная, то значение k как бы и не изменилось. В случае же переменной l, когда мы использовали var, значение l в функции, конечно, было заменено. Но в объекте o1 оно, разумеется, осталось п режним (так же как и значение k ). Конечно, польза такого необычного применения __proto__ далеко не очевидна. Однако сама возможность подобных фокусов вызывает теплые ностальгические чувства и воспоминания о Бэйсике и ассемблере конца 80-х годов прошлого века. Не будем вдаваться в подробности. У каждого своя ностальгия.

алексеи федорович
алексеи федорович
Беларусь, рогачёв
Тамара Ионова
Тамара Ионова
Россия, Нижний Новгород, НГПУ, 2009