Search code examples
javascriptobjectprototyperequirejsprivate

Private object properties


I got a RequireJs module which instances another module and proxies some methods of it. I would now like to hide the module instance itself and only allow access through the proxy-methods.

define(['mediator'], function(Mediator) {

  var Proxy;

  Proxy = function(prefix) {
    this.prefix = prefix;
    this.mediator = new Mediator();
  };

  Proxy.prototype.on = function(event, callback, context) {
    this.mediator.subscribe(this.prefix + event, callback, context || this);
  };

  Proxy.prototype.off = function(event, callback, context) {
    this.mediator.unsubscribe(this.prefix + event, callback, context || this);
  };

  Proxy.prototype.trigger = function() {
    arguments[0] = this.prefix + arguments[0];
    this.mediator.trigger.apply(this.mediator, arguments);
  };

  return Proxy;

});

require(['proxy'], function(Proxy) {

  var proxy = new Proxy('sample:');

  // this access is secured and bound to the prefix
  // I cannot mess up with other events which do not belong to me
  proxy.on('log', function(message) { console.log(message); });
  proxy.trigger('log', 'hi hello');

  // unfortunately there still would be a hack to leave my event scope
  proxy.mediator.trigger('outerscope:test', 'blabla');

});

As you see it would be possible to access the internal used mediator object of the proxy prototype and to mess up with it...

I would now like to hide the mediator instance somehow but have no idea where. I could store it in some normal variable inside the requirejs module callback but this would not work good with requirejs and could cause overlapping.

So what else can I do?

UPDATE:

define(['mediator'], function(Mediator) {

  var Proxy;

  var mediator = new Mediator();

  Proxy = function(prefix) {
    this.prefix = prefix;
  };

  Proxy.prototype.on = function(event, callback, context) {
    mediator.subscribe(this.prefix + event, callback, context || this);
  };

  Proxy.prototype.off = function(event, callback, context) {
    mediator.unsubscribe(this.prefix + event, callback, context || this);
  };

  Proxy.prototype.trigger = function() {
    arguments[0] = this.prefix + arguments[0];
    mediator.trigger.apply(this.mediator, arguments);
  };

  return Proxy;

});

require(['proxy'], function(Proxy) {

  var proxy = new Proxy('sample:');
  proxy.on('log', function(message) { console.log(message); });

});

Solution

  • This is a typical example of encapsulation of variable within closures in Javascript. What you need is to define you mediator instance as a local variable in the same scope with the Proxy. This will allow the Proxy objects to have access to Mediator via closure but will isolate Mediator from the code outside your define-callback. So like this:

    define(['mediator'], function(Mediator) {
    
        // Make mediator local scope variable
        var mediator = new Mediator(),
    
        Proxy = function(prefix) {
            this.prefix = prefix;
        };
    
        Proxy.prototype.on = function(event, callback, context) {
            mediator.subscribe(this.prefix + event, callback, context || this);
        };
    
        // ... rest of the code
    
        return Proxy;
    
    });