1

I'm playing around with a javascript object that defines some getters and setters using the Object.defineProperty method.

function User() {       
    var _username;  
    var _id;

    Object.defineProperty(User, 'id', {
        get: function() {
            return _username;
        }       
    });         

    Object.defineProperty(User, 'username', {
        get: function() {
            return _username;
        },
        set: function(username) {
            this._username = username;          
        }
    }); 
}

For one of the properties (id), I only want a getter. Originally I had a typo and it was returning the value of _username, but I quickly realized that the above did not work. Just for curiosity sake though, I'm trying to understand why it didn't work as expected. If I did the following:

var u = new User();
u.username = 'bob';
alert(u.username);
alert(u.id);

the last statement would alert undefined instead of bob. Why is that? And is there a way to get it to return another property?

user1491636
  • 2,355
  • 11
  • 44
  • 71
  • You're defining properties on `User`, not on `u`. Try `User.username` to see it work - and then fix your code not to alter the constructor function. – Bergi Nov 27 '14 at 21:46

1 Answers1

1

You must define the properties on this instead of the constructor function

function User(params) {       
   var _username;

   Object.defineProperty(this, 'id', {
        get: function() {
            return _username;
        }       
   });         

   Object.defineProperty(this, 'username', {
        get: function() {
            return _username;
        },
        set: function(username) {
            _username = username;          
        }
   }); 
   if (params && params.username) {
       this.username = params.username;
   }
}
User.prototype.stringify = function () {
    return JSON.stringify({ username: this.username});
}
Jeanluca Scaljeri
  • 26,343
  • 56
  • 205
  • 333
  • Changing it to `this` doesn't seem to work. If I do that and I run the user test code in my original post, the first and second alert both output `undefined`. – user1491636 Nov 27 '14 at 22:20
  • This should work, could you show me what you did (in a [jsfiddle](http://jsfiddle.net/) for example) ? – Jeanluca Scaljeri Nov 28 '14 at 07:23
  • 1
    If you replace `User` with `this` you're half way :) I've made more changes to your code, I admit they are subtile! Note that you have `var _username` and `this._username`!! – Jeanluca Scaljeri Nov 28 '14 at 15:36
  • Follow-up question. With the above solution implemented, why can't I do something like this: `var u1 = new User(); u1.username = 'a'; var u2 = new User(); u2.username = 'b';` This is essentially what I am trying to achieve; create distinct objects and assign different values to them. – user1491636 Dec 02 '14 at 14:24
  • But you can. What is exactly the problem you're experiencing ? – Jeanluca Scaljeri Dec 02 '14 at 17:00
  • My bad. Was using an out of date version. Please ignore. – user1491636 Dec 02 '14 at 17:51
  • One thing I notice now though is that I can't stringify an instance of User. It ends up being {} without any of the properties or values. Why is that? – user1491636 Dec 02 '14 at 18:43
  • 1
    JSON.stringify will strip off things like functions. Because you've defined a getter/setter on `username` its stripped off now. For example, if you do: `x = new User;x.abc = 1;JSON.stringify(x);` you see what I mean. You could of course define your own `stringify` function (checkout my origin post) – Jeanluca Scaljeri Dec 02 '14 at 19:35
  • What about the reverse now? Would I defined a parse method to return a new instance of User? – user1491636 Dec 02 '14 at 21:02
  • No, just accept an json object in the constructor function and initialize it inside there, like: `var x = new User({username: 'A'});` – Jeanluca Scaljeri Dec 03 '14 at 09:01