JS defineProperty and prototype

Please don't implement any other version because it will eat all your memory in your app:

var Player = function(){this.__gold = 0};

Player.prototype = {

    get gold(){
        return this.__gold * 2;
    },



    set gold(gold){
        this.__gold = gold;
    },
};

var p = new Player();
p.gold = 2;
alert(p.gold); // 4

If 10000 objects are instantiated:

  • With my method: you will only have 2 functions in the memory;
  • With the other methods: 10000 * 2 = 20000 functions in the memory;

It seems to me, that when you defineProperties for prototype, all instances shares that properties. So the right variant could be

var User = (function(){
// constructor
function User(id, name){
    this.id     = id
    this.name   = name

    Object.defineProperty(this, "name", {
        get: function(){ return name },
        set: function(new_value){
            //Some business logic, upperCase, for example
            new_value = new_value.toUpperCase();
            name = new_value
        }
    })
}
return User;
})();

I came to the same conclusion as Mikhail Kraynov three minutes after he answered. That solution defines new properties each time the constructor is called. I wondered if, as you asked, there was a way of putting the getters and setters in the prototype. Here is what I came up with:

var User = (function () {
  function User (id, nam) {
    Object.defineProperty (this, '__',  // Define property for field values   
       { value: {} });

    this.id = id;
    this.nam = nam;
  }

  (function define_fields (fields){
    fields.forEach (function (field_name) {
      Object.defineProperty (User.prototype, field_name, {
        get: function () { return this.__ [field_name]; },
        set: function (new_value) {
               // some business logic goes here 
               this.__[field_name] = new_value;
             }
      });
    });
  }) (fields);

  return User;
}) ();  

In this solution I define the field getters and setters in the prototype but reference a (hidden) property in each instance which holds the field values.

See the fiddle here : http://jsfiddle.net/Ca7yq

I added some more code to the fiddle to show some effects on enumeration of properties : http://jsfiddle.net/Ca7yq/1/


As you define your properties on the prototype object of all user instances, all those objects will share the same value variable. If that is not what you want, you will need to call defineFields on each user instance separately - in the constructor:

function User(id, name){
    this.define_fields(["name", "id"]);
    this.id     = id
    this.name   = name
}
User.prototype.define_fields = function(fields) {
    var user = this;
    fields.forEach(function(field_name) {
        var value;
        Object.defineProperty(user, field_name, {
            get: function(){ return value; },
            set: function(new_value){
                /* some business logic goes here */
                value = new_value;
            }
        });
    });
};