Jedną z największych magicznych mocy wszystkich frameworków i pluginów javascript jest możliwość rozszerzenia ich działania poprzez tak zwane callbacks. Pokażę Wam jak wykonać własny obiekt javascript, który będzie potrafił je obsłużyć.
Po pierwsze potrzebujesz zdefiniować swoją klasę:
function myClass(params){
}
Prościzna ;) Spróbujmy teraz obsłużyć callback beforeInit, który odpali się “najsampierw” przy tworzeniu obiektu:
function myClass(params){
if(params.beforeInit){
console.log("beforeInit");
params.beforeInit();
}
console.log("Init complete")
}
console.log("=============");
var a = new myClass(
{
beforeInit: function(){console.log("My message!");}
}
);
Włącz firebuga i sprawdź działanie ;)
============= beforeInit My message! Init complete
Oczywiście Twoja klasa może zechcieć coś zrobić oprócz stworzenia siebie samej ;) Callbacki mogą zachowywać się różnie w zależności od stanu obiektu. Do klasy dodałem metodę doSth i callback beforeRun (który wykonuje się przed wykonaniem metody doSth)
Wypróbuj następujący kod:
function myClass(params){
if(params.beforeInit){
console.log("#beforeInit");
params.beforeInit();
}
this.doSth = function() {
if(params.beforeRun){
params.beforeRun(this.state);
}
console.log("#doSth");
}
if(params.state) {
this.state = params.state;
}else{
this.state = false;
}
console.log("Init complete")
}
console.log("=============");
var a = new myClass(
{
state: 1,
beforeRun: function(state){
if(state != false) {
console.log("Extended! state = " + state);
}else {
//do nothing
}
}
}
);
a.doSth();
console.log("=============");
var b = new myClass(
{
beforeRun: function(state){
if(state != false) {
console.log("Extended! state = " + state);
}else {
//do nothing
}
}
}
);
b.doSth();
wynik:
============= Init complete Extended! state = 1 #doSth ============= Init complete #doSth
Możesz też uzależnić wykonanie metody doSth w zależności od warunków wewnętrznych (parametr state) lub zewnętrznych:
function myClass(params){
if(params.beforeInit){
console.log("#beforeInit");
params.beforeInit();
}
this.doSth = function() {
if(params.beforeRun){
if(!params.beforeRun(this.state)){
return;
}
}
console.log("#doSth");
}
if(params.state) {
this.state = params.state;
}else{
this.state = false;
}
console.log("Init complete")
}
console.log("=============");
var a = new myClass(
{
state: 1,
beforeRun: function(state){
if(state != false) {
console.log("Extended! state = " + state);
}else {
return false
}
}
}
);
a.doSth();
console.log("=============");
var b = new myClass(
{
beforeRun: function(state){
if(state != false) {
console.log("Extended! state = " + state);
}else {
return false
}
}
}
);
b.doSth();
console.log("=============");
var c = new myClass(
{
beforeRun: function(state){
if( (new Date().getTime())%2 ) {
console.log("Extended! state = " + state);
}else {
return false
}
}
}
);
c.doSth();
Wynik (zależy od aktualnego czasu, więc może okazać się konieczne uruchomienie go kilka razy, zanim otrzymasz identyczny):
============= Init complete Extended! state = 1 ============= Init complete ============= Init complete Extended! state = false
W przypadku obiektu c metoda run odpali się tylko, jeśli aktualny timestamp jest podzielny przez 2 ;)
To tyle. Mam nadzieję, że pozwoli Wam to wymyślać ciekawsze i bardziej użyteczne fragmenty kodu javascript, nawet tego używanego prywatnie.
Sprytnie zaprojektowana klasa ze sprytnymi callbackami jest bardzo przyjemna – możliwe jest modyfikowanie jej zachowania bez modyfikacji klasy bazowej. To samo podejście znacie pewnie z Behaviors cake’a.