Московский физико-технический институт
Опубликован: 23.12.2005 | Доступ: свободный | Студентов: 2868 / 252 | Оценка: 4.61 / 4.44 | Длительность: 27:18:00
ISBN: 978-5-9556-0051-2
Лекция 6:

Классы

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

Аппетит приходит во время еды; теперь мы можем вспомнить о том, что в C++ и Java бывают также и статические методы. Им разрешен доступ только к статическим полям и методам класса, но вызывать их можно как через класс, так и через объект. Раз уж поля мы сделали статическими, никто не мешает сделать статическими и методы. К статическим свойствам эти методы будут обращаться через класс. Более того, и вызваны эти методы должны быть как методы класса (то есть как если бы они были полями объекта -функции конструктора ). Тогда this в этих методах будет указывать на класс, а не на конкретный объект. Иначе статические методы получат доступ и к обычным (не статическим) полям и методам, чего мы как раз хотим избежать. Таким образом, для заводимых в прототипе ссылок на нужные нам статические методы мы должны будем где-то сохранить ссылку на класс (то есть его конструктор ). Далее мы будем следовать методике Тимоти Гролео и хранить все нужные вещи в контексте вызова функции addStaticMethod, которая приведена ниже.

// Для тестирования нам надо добавлять не только статические
	// методы, но и свойства. Здесь используем более простой
	// вариант кода, без пользовательских getter'ов setter'ов
Function.prototype.addStaticProperty = function(name, propVal){
		// Храним значение прямо в контексте вызова
		// addStaticProperty, прямо в аргументе ее.
	var getter = function() {
  	return propVal;
 	}
 	var setter = function(newVal) {
  	propVal = newVal;
 	}
		// Как сам конструктор, так и прототип должны получить
		// это свойство (ссылающееся на одни и те же данные).
	this.addProperty(name, getter, setter);
  this.prototype.addProperty(name, getter, setter);
}
	// Прячем метод от for...in, наподобие системных методов
	// В принципе, этого можно и не делать.
ASSetPropFlags(Function.prototype, "addStaticProperty", 1);
	// Простейший вариант добавления статического метода
Function.prototype.addStaticMethod = function(name, staticMethodEngene) {
	var theClass = this;
	var staticMethod = function() {
		return staticMethodEngene.apply(theClass, 
arguments);
 	};
 	this[name] = staticMethod;
 	this.prototype[name] = staticMethod;
}
	// Прячем метод от for...in, наподобие системных методов
	// В принципе, этого можно и не делать.
ASSetPropFlags(Function.prototype, "addStaticMethod", 1);
	// Тестируем статическое свойство
_global.SomeClass = function(){}
SomeClass.addStaticProperty("testProp", "Тестовое значение");
a = new SomeClass();
b = new SomeClass();
trace(a.testProp);
SomeClass.testProp = "Второе тестовое значение";
trace(b.testProp)
b.testProp = "Третье тестовое значение";
trace(SomeClass.testProp);
	// Тестируем статический метод
b.someStr = "Некоторая строка";
f = function(){
	trace("this.testProp.toLowerCase = " + this.testProp.toLowerCase());
	trace("this.someStr = " + this.someStr);
}
SomeClass.addStaticMethod("printTest", f);
trace("");
trace("--- b.printTest() ----");
b.printTest();
trace("--------------");
trace("");
trace("--- SomeClass.printTest() ----");
SomeClass.printTest();
trace("------------------");
trace("");
trace("b.someStr = " + b.someStr);

Выводит этот код, как и ожидалось,

Тестовое значение
Второе тестовое значение
Третье тестовое значение
--- b.printTest() ----
this.testProp.toLowerCase = третье тестовое значение
this.someStr =
--------------
--- SomeClass.printTest() ----
this.testProp.toLowerCase = третье тестовое значение
this.someStr =
------------------
b.someStr = Некоторая строка

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

Для более глубокого понимания происходящих здесь вещей попробуйте угадать, что выведет вызов b.printTest() в том случае, когда мы добавим f не с помощью addStaticMethod, а с помощью addStaticProperty. Для того чтобы побольше запутать вас, приведем сначала неправильный способ рассуждений. Он состоит в том, что getter возвращает объект -функцию, который хранится в контексте вызова addStaticProperty. Тогда this указывает на этот контекст, в котором отсутствуют как testProp, так и someStr. Таким образом, вместо их значений мы получим пустоту. Следующая мысль, которая приходит в голову, - это то, что getter, возвращая ссылку на объект -функцию, сохраняет ее в неком временном хранилище, к которому и будет относиться this. (Для сравнения загляните в лекцию 5, параграф "Функция как объект " и еще раз просмотрите пример, иллюстрирующий использование возвращаемых значений типа Function.) Вывод тот же самый - мы увидим пустое место вместо значений строк. Однако запустите наш код, заменив вызов addStaticMethod на addStaticProperty. И вы увидите, что будет выведен, в частности, следующий фрагмент:

--- b.printTest() ----
this.testProp.toLowerCase = третье тестовое значение
this.someStr = Некоторая строка
--------------

Правильное же решение, которое полностью избавляет от всех сомнений, состоит в том, что Flash MX делает поведение свойств максимально похожим на поведение обычных полей. Так что раз уж мы написали b.printTest(), то в функцию printTest в качестве this будет передана именно ссылка на b. А то, что ссылка на printTest хранится где-то в другом месте (не в b ) и нам ее возвращает getter - это нас волновать уже не должно.