0

JavaScript is dynamic. Cool !

I have the following constructor function :

function Preferences () {

  this._preferences = {}

}

var obj = new Preferences()

I want to achieve something like this:

>>> obj.something = 'value'
>>> this._preferences['something']
    'value'

That is setting the property of the obj does not actually set it's own property but that of obj._preferences. That is I want to override the default behavior.

Is it possible ?

EDIT : I want to achieve this for all property names i.e the name of the property to be set is not already known.

darxtrix
  • 2,032
  • 2
  • 23
  • 30
  • It sure is - have a look at [getters/setters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty#Custom_Setters_and_Getters). – Robert Rossmann Jun 11 '15 at 12:19
  • 2
    If you want to do with for specific property names, you can use `Object.defineProperty`. If you want to do this for all property names, you need an ES6 `Proxy`. – apsillers Jun 11 '15 at 12:22
  • 1
    possibly a duplicate of [Javascript overloading dot](http://stackoverflow.com/questions/4569296/javascript-overloading-dot); you will need to use the `--harmony-proxies` command-line flag when starting Node – apsillers Jun 11 '15 at 12:28
  • @apsillers , I guess using that would be not good, due to the support issues. But thanks for pointing it out. – darxtrix Jun 11 '15 at 12:31
  • @black-perl I'm not sure what support issues you're concerned about -- do you need to do this in a browser client? Your question is tagged `[node.js]`, so I assumed you wanted to do this on the server (where you can always control what server version you run). Just make sure you're running a modern (i.e., more recent than 2013, maybe) installation of Node.js. – apsillers Jun 11 '15 at 12:35
  • @apsillers, yeah sure ! – darxtrix Jun 11 '15 at 13:48

2 Answers2

4
Object.defineProperty(Preferences.prototype, 'something', {
  get: function(){
    return this._preferences.something;
  },
  set: function(value){
    this._preferences.something = value;
  }
});

should do it. It defines a property, 'something', using an accessor property instead of a data property, and will call the 'get' and 'set' functions to decide what do so when .something is accessed.

loganfsmyth
  • 156,129
  • 30
  • 331
  • 251
  • It requires the knowledge of property names before hand. – darxtrix Jun 11 '15 at 12:27
  • 1
    Unfortunately that is not possible at the moment. It's doable with ES6 proxies or [Object.observe](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/observe) but those are brand new features that are not well supported yet. – loganfsmyth Jun 11 '15 at 12:31
0

SOLUTION 1

Using Proxy object you can do something like this and handle runtime defined properties

function Preferences() {
  this._preferences = {};

  var prefProxy = new Proxy(this, {
    get: function(target, property) {  
      return property in target? 
              target[property]:
              target._preferences[property];
    }

    set: function(target, property, value, receiver) {
      if(property in target){
        target[property] = value;
      } else {
        target._preferences[property] = value;
      }
    }

  });


  return prefProxy;  
};

SOLUTION 2

I can be wrong but i think what you are asking is solved returning _preferences

function Preferences () {

  this._preferences = {};

  return _preferences;
}

var obj = new Preferences()

SOLUTION 3

Using getter and setter you can redirect the property to _preferences

function Preferences () {

  this._preferences = {}

  Object.defineProperty(Preferences.prototype, 'something', {
    get: function() {
        return this._preferences['something'];
    },
    set: function(value) {
       this._preferences['something'] = value; 
    }
  });


}

var obj = new Preferences()
SharpEdge
  • 1,782
  • 1
  • 10
  • 20