views:

172

answers:

1

I need to extend a class, which is encapsulated in a closure. This base class is following:

var PageController = (function(){

    // private static variable
    var _current_view;

return function(request, new_view) {
    ...

    // priveleged public function, which has access to the _current_view 
    this.execute = function() {
        alert("PageController::execute");
    }

}
})();

Inheritance is realised using the following function:

function extend(subClass, superClass){
var F = function(){
};
F.prototype = superClass.prototype;
subClass.prototype = new F();
subClass.prototype.constructor = subClass;
subClass.superclass = superClass.prototype;
StartController.cache = '';


if (superClass.prototype.constructor == Object.prototype.constructor) {
    superClass.prototype.constructor = superClass;
}
}

I subclass the PageController:

var StartController = function(request){
    // calling the constructor of the super class
    StartController.superclass.constructor.call(this, request, 'start-view');
}
// extending the objects
extend(StartController, PageController);

// overriding the PageController::execute
StartController.prototype.execute = function() {
alert('StartController::execute');
}

Inheritance is working. I can call every PageController's method from StartController's instance. However, method overriding doesn't work:

var startCont = new StartController();
startCont.execute();

alerts "PageController::execute". How should I override this method?

+2  A: 

It doesn't work because StartController calls PageController which adds an execute property to your object, so the execute property of StartController.prototype is not used.

For your overriding to work, you have to either :

1) define PageController.prototype.execute as the execute method of PageController. It won't work because then the function doesn't have access to _current_view.

2) define StartController.execute in the object constructor :

var StartController = function(request){
    // calling the constructor of the super class
    StartController.superclass.constructor.call(this, request, 'start-view');
    // overriding the PageController::execute
    this.execute = function() {
      alert('StartController::execute');
    }
}
// extending the objects
extend(StartController, PageController);

edit:

So you want for StartController.execute to access _current_view, which is impossible as long as _current_view is part of a closure that StartController is not part of. You might have to proceed like this:

(function () {
  var _current_view;
  window.PageController = function(request, new_view) {
   ...
   this.execute = function() { ... }
  }

  window.StartController = function(request) {
    StartController.superclass.constructor.call(this, request, 'start-view');
    this.execute = function() { ... }
  }
  extend(StartController, PageController);

}()
var startCont = new StartController();
startCont.execute();

And if you want some kind of protected behavior, you might want to try this trick:

(function() {
  var token = {};

 window.Class1 = function() {
    this.protectedMethod = function(tok) {
      if(tok != token) return; // unauthorized
      ...
    }
  }

  window.Class2 = function() {
    new Class1().protectedMethod(token); // access granted
  }
})()

new Class1().protectedMethod(); // access denied

There's no such thing as a package in javascript, so your possibilities are limited. You can certainly not have any kind of privileges among functions/objects/constructors that are not part of the same script. None that I know of, at least. Except maybe querying a server for some kind of authorization.

Alsciende
The second method doesn't have the access to _current_view either. However, now I'm not sure that my design decision with closure was right. _current_view is static and private, but I need an access to _current_view from subclasses and this is more like a "protected" behaviour. I could make public accessor methods for _current_view, but it would allow everybody to modify _current_view and I want to avoid this.Btw, are there any techniques to emulate "protected" variables?
bobikk
Yes, there are. I will update my answer to help you on that point. But my current answer fits your question, since you didn't ask for StartController to access _current_view, right?
Alsciende
Thank you for your truly detailed and comprehensive answer. I think, I'm starting to understand concepts of JavaScript better. Thanks!
bobikk