1

I came up with the situation below:

function Dog () {
    "use strict";
    this.age = 1;
    var name = "Fido";
    this.getName = function () { return name; }
}

And now I'm creating a new instance of the "Dog" class and printing the variable's values.

var d = new Dog;
document.write('<strong>Dog age:</strong> ' +d.age); \\Outputs "1" as expected
document.write('<br/>');
document.write('<strong>Dog name:</strong> ' +d.name); \\Outputs "undefined" as expected, 'cause it's a private variable.
document.write('<br/>');
document.write('<strong>Get Dog name:</strong> ' +d.getName()); \\Outputs "Fido", as expected.

But let's say I want to change the Dog's name, like this:

d.name = "Stinky";
document.write('<br/>');
document.write('<strong>Dog name Again:</strong> ' +d.name); 
document.write('<br/>');
document.write('<strong>Get Dog name Again:</strong> ' +d.getName());

Based on this, I got a couple of questions:

  1. Why on earth "d.name" didn't showed me "undefined"? Isn't "name" a private variable? I suppose you can't change private variables values, am I right? I wonder if this process have created a new variable, but this time, a public one, and with the same name. If so, is there a way to prevent the creation of new variables every time I try to assign a new property with the same name? Is there a way to throw a "type error" or something (well, this was what I expected).
  2. And at last: Why "getName" printed the original value, "Fido", even after I assigned a new value to it ?

Any ideas?

Here's a fid to make things easier.

http://fiddle.jshell.net/yZpfg/2/

Alex Wayne
  • 178,991
  • 47
  • 309
  • 337
darksoulsong
  • 13,988
  • 14
  • 47
  • 90
  • It outputs `undefined` simply because the property doesn't flat out exist on the object, not because there is a private property on the object – Esailija Jul 24 '12 at 17:50
  • You are going to need a better understanding of [closures](http://en.wikipedia.org/wiki/Closure_(computer_science)) before you'll begin to understand whats going on here. – J. Holmes Jul 24 '12 at 17:52
  • It's time you read about [getters and setters](http://stackoverflow.com/questions/812961/javascript-getters-and-setters-for-dummies). – Matt Ball Jul 24 '12 at 17:52
  • Javascript does not have such things like "public" or "private" properties. Properties are always public. You can only achieve some sort of "pseudo"-privacy with the help of closures which makes use of the function-scope of JS (which is the case with your variable name). – Christoph Jul 24 '12 at 18:04

3 Answers3

6

d.name = "Stinky"; is adding a new (public) property to to the d object, which is an instanceOf Dog.

the getter still references the (private) variable with the value Fido.

If you want to allow a consumer to change a private variable, you need a setter as well:

function Dog () {
    "use strict";
    this.age = 1;
    var name = "Fido";
    this.getName = function () { return name; }
    this.setName = function (value) { name = value; }
}

var d = new Dog(); 
d.name; // undefined because there is no name public property
d.getName() // returns the internal private, "Fido"
d.setName('Stinky'); // the internal private is now "Stinky"
jbabey
  • 45,965
  • 12
  • 71
  • 94
  • 2
    Just to be clear (in case "dog object" is confusing), it's adding a new property to the `d` object (the instance of `Dog`). It's not adding a new property to `Dog` itself. – James Allardice Jul 24 '12 at 17:52
  • Javascript does not have such things like "public" or "private" properties. You can only achieve some sort of "pseudo"-privacy with the help of closures (which is the case with your variable `name`). (Hm, actually this was supposed to be a comment to the question...) – Christoph Jul 24 '12 at 18:03
  • @Christoph it's a scope, not a closure, and it's easier to just call them "public" and "private". – jbabey Jul 24 '12 at 18:04
  • @jbabey it's a closure - because of the getter-function the var `name` exists beyond the scope of the original function. The only thing is, that the variable is not accessible publicly anymore. – Christoph Jul 24 '12 at 18:06
  • Devil's advocate: "A closure is formed by returning a function object that was created within an execution context of a function call from that function call and assigning a reference to that inner function to a property of another object." http://jibbering.com/faq/notes/closures/#clFrmC – jbabey Jul 24 '12 at 18:10
  • @jbabey - See "Myth No. 1" in [this article](http://javascriptweblog.wordpress.com/2010/10/25/understanding-javascript-closures/) – James Allardice Jul 24 '12 at 18:14
  • Thanks everyone. I'm still learning and all responses were very illustrative. – darksoulsong Jul 24 '12 at 18:18
  • well, jbabey looks like you answered this for yourself;) – Christoph Jul 24 '12 at 18:20
1

You're confusing local variables with instance properties. These are totally separate.

1) You set d.name, an instance property, and it's this you're calling, not the private variable.

2) Fido is the valeu of the private var, which is what your method returns, not the instance property, so the method will always say Fido.

Your original code should probably look like this:

function Dog () {
    "use strict";
    this.age = 1;
    this.name = "Fido";
}
Dog.prototype.getName = function() { return this.name; }

Note I add the method to the prototype rather than explicitly adding it to each instance. This way, the instance inherits it. This is better practice; reusable code should be on the prototype, and it's better performing than adding it each time to every instance.

Mitya
  • 33,629
  • 9
  • 60
  • 107
1

var name inside your constructor and someObj.name are never ever going to be the same thing. 2 different values that can be set to 2 different things. Instead, you need a setter function that works like your getter:

this.setName = function(newName) { name = newName; };

There is no way to raise an error when setting a property that has the same name as a private variable. They are 2 completely different things, and there is no callback when a property is set that you could even intercept.

Alex Wayne
  • 178,991
  • 47
  • 309
  • 337