5

The following doesn't work, from my getter, I can't see _nickname defined in the 'class' Person.

var Person = function (args) {

    var _nickname = '';
    if (args === undefined || args === null) {
        return;
    }
    if (args.nickname !== undefined && args.nickname !== null) {
        _nickname = args.nickname;
    }

}

Object.defineProperty(Person.prototype, "nickname", {
    get : function () {
        return _nickname;
    }
});

var x = new Person({
        nickname : 'bob'
    });

console.log(x.nickname);

How should one go about accomplishing this? Is there a way of adding _nickname to the prototype of Person from within its function?

Matt
  • 25,943
  • 66
  • 198
  • 303
  • Quick tip: `args === undefined || args === null` same as `args == null` because `null == undefined`. Same thing with other comparison. – elclanrs Aug 21 '13 at 22:14
  • Ah yeah, I was being finicky about JsLint and he doesn't like the ==. I corrected it. I don't know if I'm being too cautious, but I was hoping JS closure would take care of it :-) – Matt Aug 21 '13 at 22:15
  • 3
    JSHint is my cup of tea. It has an option just for this particular case: [eqnull](http://www.jshint.com/docs/options/#eqnull) – elclanrs Aug 21 '13 at 22:17

1 Answers1

6

Is there a way of adding _nickname to the prototype of Person from within its function?

If you mean the Person constructor, sure (although in my opinion it doesn't look very elegant):

var Person = function (args) {
    var _nickname = '';
    if (args === undefined || args === null) {
        return;
    }
    if (args.nickname !== undefined && args.nickname !== null) {
        _nickname = args.nickname;
    }
    Object.defineProperty(this, "nickname", {
        get : function () {
            return _nickname;
        }
    });
}

var x = new Person({
    nickname : 'bob'
});

console.log(x.nickname);

http://jsfiddle.net/JEbds/

In this case, your getter is just another closure, so it has access to _nickname. And it's not on the prototype anymore, you need an own property to accomplish that.

bfavaretto
  • 71,580
  • 16
  • 111
  • 150
  • But won't Object.defineProperty run every time I do 'new Person()'? Or is that not a big deal? That's really what I wanted to avoid. – Matt Aug 21 '13 at 22:33
  • It does. But if you don't run it from the constructor, it will never be able to access `_nickname`. – bfavaretto Aug 21 '13 at 22:41
  • 1
    @Matt If you're okay with it not being really private, you can use `this._nickname` (and you can even set it `writable: false`, so the value set in the constructor can never be changed). http://jsfiddle.net/669Gb/ – bfavaretto Aug 21 '13 at 22:42
  • @bfavaretto Note that if you were to use defineProperty to define the string value _nickname it would not be writable (because string is immutable) but if _nickname were a mutable object it will be writable (not directly but through the object's functions). Let's say _nickname is an array and in the Person constructor we do: `Object.defineProperty(this, "_nickname", {value:[]})` with a person instance we do `p._nickname=22;` then nothing will happen and _nickname is still [] but if we do: `p._nickname.push(22);` Then p._nickname will be [22]. – HMR Aug 22 '13 at 00:42
  • 3
    @Matt There is realy no good way to have private instance value properties (properties that have unique private values for each instance). You can have shared "private" functions on the prototype or shared value property where the value is shared among all instances. "Private" functions: http://stackoverflow.com/questions/18320934/how-to-call-parent-class-method-from-a-subclass-in-javascript-so-that-parents/18325012#18325012 Using constructor functions and prototype: http://stackoverflow.com/questions/16063394/prototypical-inheritance-writing-up/16063711#16063711 – HMR Aug 22 '13 at 00:52
  • @HMR Yes, if [[writable]] is false it only prevents assignments (but I don't think it has to do with strings being immutable). If the value is an object or an array, I believe you can still freeze the object (although I don't have much experience with that). – bfavaretto Aug 22 '13 at 00:54
  • @bfavaretto `false it only prevents assignments` `I don't think it has to do with stings being immutable` immutable means that you can only change the value of the immutable object/primitive through assignment. You set writable to false so you can't change these properties. For mutable objects have functions that will change their internal values (push in array) string is immutable because all it's functions will not change the internal value of string (.toLowerCase, .toUpperCase will return a value but not change the string itself) – HMR Aug 22 '13 at 00:58
  • @HMR Right, I misunderstood your previous statement. – bfavaretto Aug 22 '13 at 00:59