Беларусь, рогачёв |
Классы
Изменяемые статические методы
Что делать, если мы хотим изменить поведение статического метода, созданного нами? Простейший способ - снова вызвать addStaticMethod и передать ему в качестве первого аргумента то же самое имя метода, а вот в качестве второго - уже другую функцию. Однако великий и ужасный Тимоти Гролео предлагает другое решение. Это решение хорошо тем, что мы можем просто присваивать свойству, через которое мы доступаемся к нашему статическому методу, любую функцию; главное, чтобы эта функция подразумевала, что this внутри нее - ссылка на класс (то есть конструктор ). Такое поведение удобно, особенно если мы передаем объекты с уже созданными там статическими методами в код, уже давно созданный и предполагающий именно такое (стандартное) поведение. Или же этот код будет создаваться другими людьми и нам проще им сказать "все работает как обычно", чем объяснять, что надо всякий раз вызывать addStaticMethod. Итак, новая версия addStaticMethod от Гролео, позволяющая просто присваивать новые статические методы на место старых, вылядит так:
Function.prototype.addStaticMethod = function(name, staticMethodEngene) { var theClass = this; var getter = function() { return staticMethodEngene; }; // Setter должен сгенерировать новый метод - который вызовет // newMethod, // передав ему theClass в качестве this. var setter = function(newMethod) { staticMethodEngene = function() { return newMethod.apply(theClass, arguments); }; }; setter(staticMethodEngene); this.addProperty(name, getter, setter); this.prototype.addProperty(name, getter, setter); }
Заменим на этот вариант addStaticMethod из предыдущего примера; и добавим в конце примера следующий проверочный код:
g = function(){ trace("Функция g вступает в работу."); trace("this.testProp.toUpperCase = " + this.testProp.toUpperCase()); trace("this.someStr = " + this.someStr); } trace(""); SomeClass.printTest = g; trace("Произведена замена функции: SomeClass.printTest = g;"); trace(""); trace("--- b.printTest() ----"); b.printTest(); trace("--------------");
Запускаем все это и получаем:
Тестовое значение Второе тестовое значение Третье тестовое значение --- b.printTest() ---- this.testProp.toLowerCase = третье тестовое значение this.someStr = -------------- --- SomeClass.printTest() ---- this.testProp.toLowerCase = третье тестовое значение this.someStr = ------------------ b.someStr = Некоторая строка Произведена замена функции: SomeClass.printTest = g; --- b.printTest() ---- Функция g вступает в работу. this.testProp.toUpperCase = ТРЕТЬЕ ТЕСТОВОЕ ЗНАЧЕНИЕ this.someStr = --------------
Итак, setter сработал как надо: сгенерировал новую функцию, которая вызывает g, передавая ей с помощью apply ссылку на объект -функцию конструктора. И далее при работе g эта ссылка используется в качестве this. Таким образом, мы действительно получили доступ к статическому свойству testProp и не получили - к обычному полю объекта b (а именно, к полю someStr ).