0

Update: 2012.06.26 - See my conclusion bellow my original question.

I'm trying to figure out why this simple code doesn't initialize correctly. Yes, I'm from the Java world and I'm also a 'purist' and would like to do JavaScript properly.

Many (if not all) will recommend to declare the variables prefixed with a 'this' keyword and thus exposing all those variables without using proper setter and getter functions. To me this is unacceptable and does not reflect good OOP practice. They say JavaScript is an OOP language so why do people always try to bypass this I'll never understand!? But that's not the questions, so lets move on...

The problem with the following code is that when I run it in Chrome, it keeps telling me:

Uncaught ReferenceError: x is not defined

I could create a constructor which accepts the default values, but I'd rather not expose what the default value is suppose to be on those constructing the object (that is not good practice either). Also, during run-time, the setter methods would get invoked to change the 'x' and 'y' values for a specific instance. There are many 'Model' instances available at once!

So here is the simple code:

function Model() {
    var x = 3;
    var y = 'hello';
}

Model.prototype.getX = function() {
    return x;
}

Model.prototype.getY = function() {
    return y;
}

Model.prototype.setX = function(myX) {
    x =  myX;
}

Model.prototype.setY = function(myY) {
    y =  myY;
}

var model = new Model();

console.log("Model Y = '" + model.getY() + "'");
console.log("Model X = " + model.getX());
console.log("Model Y = '" + model.getY() + "'");

Thanks for your help...

Conclusion to the question (updated on 2012.06.26):

It is quite easy to conclude that what was requested (which happens to be something so simple) can not be done with JavaScript!

To my utmost surprise thought, as can be seen from the answers bellow, some will argue that since JavaScript does not support it, then you shouldn't need it or use it. Wow, that's really amazing!

I have argued for many years that JavaScript was not an OOP language and this simple question (and it's answers) goes to prove it.

So in the end it discusses me to admit defeat and you and I will both need to change our code to using the 'this' keyword for all class members. Once again, the language controls the programmer rather than the programmer controlling the language! And they wonder why over 2/3 of software projects fail every year!?

Jeach
  • 8,656
  • 7
  • 45
  • 58
  • 3
    JavaScript isn't Java. The two languages are quite different, and in particular the object and inheritance models are **completely** different. – Pointy Jun 25 '12 at 15:46
  • Private variables are only available in the scope that they are declared as well as within methods declared within that scope. – dqhendricks Jun 25 '12 at 15:47
  • Apparently even Java cannot enforce privacy (http://tutorials.jenkov.com/java-reflection/private-fields-and-methods.html) Why should javascript? – Esailija Jun 25 '12 at 15:47
  • @Pointy: Believe me, I know JavaScript is not Java! And they have different models, so are you working around to admitting what I'm trying to do is not possible? – Jeach Jun 25 '12 at 19:08
  • @Esailija: What are you talking about? The first paragraph of your article clearly mentions the security sandbox! Reflection is a 'possible' way around it, if the security is left open, otherwise Java does 'private' members! So I guess from your justification that your saying JavaScript can not have private variables? – Jeach Jun 25 '12 at 19:10
  • @Jeach I'm not familiar with Java but in the article it said that it's *not something that you need to do very often* . Is it incorrect? Anyway, my point is that you don't need **enforced** privacy. – Esailija Jun 25 '12 at 19:15
  • @Esailija: True, I wouldn't need to enforce privacy 'IF' there wouldn't be programmers that would try to set values directly. Being that we are in an imperfect world, we have such programmers and I find that I require such level of privacy. I'd like to note that there are decades of academic research which have tried to enhance languages and make them better by adding privacy to a language. It's not some guy that woke up and said "hey, let's allow private members just so everyone can ignore them". When one promotes "you don't need privacy", you put aside decades of language advancements. – Jeach Jun 25 '12 at 20:54

3 Answers3

3

One way is to define getX and getY inside Model and not with prototype.

function Model() {
    var x = 3;
    var y = 'hello';
    this.getX = function(){return x;}
    this.getY = function(){return y;}
    this.setX = function(val){x=val;}
    this.setY = function(val){y=val;}
}

var foo = new Model();
console.log(foo.getX());

There are other ways of doing it, this is the simplest in my eyes.

epascarello
  • 204,599
  • 20
  • 195
  • 236
  • *There are other ways of doing it*; this is the ***only*** pattern which properly supports private variables, no? The downside of this is that each instance of `Model` has it's own copy of `getX` and `getY`, but this is only important if you instantiate a large number of `Model` objects. – Matt Jun 25 '12 at 15:49
  • 1
    I think so. But it multiplies the functions. – Denys Séguret Jun 25 '12 at 15:50
  • @dystroy: Indeed, but I think the effects of that are *massively* exaggerated, unless you instantiate a large number of `Model` objects. – Matt Jun 25 '12 at 15:51
  • Yes but what is the gain of having real private fields ? – Denys Séguret Jun 25 '12 at 15:52
  • @dystroy: I didn't say there were any ;); FWIW I've upvoted both this and your answer. A thing to note using your approach (`_`) is that debugging is a hell of a lot easier, because the values of the private variables are printed to the console (`console.log(this)`). – Matt Jun 25 '12 at 15:53
  • A question I never asked myself : is it really impossible to gain access to the closure of a function ? I know it is visible in Chrome debugger... – Denys Séguret Jun 25 '12 at 15:56
  • @dystroy: I don't know a way to do it programmatically, and Google hints towards it being impossible as well. – Matt Jun 25 '12 at 16:00
  • 2
    It would be easier just to use Dart or GWT than manage code written like this – Esailija Jun 25 '12 at 16:01
  • http://stackoverflow.com/questions/11192875/is-it-possible-to-gain-access-to-the-closure-of-a-function – Denys Séguret Jun 25 '12 at 16:01
  • @dystroy: Are you freaking serious in your response? Questioning the gain of having private fields? I guess you are one of those guys who promote JavaScript as being an OOP language but then make comments like this. There are a TON of gains to encapsulating members and requiring using getters and setter methods, but I sure as hell won't give you this lesson here. BTW, my original question is NOT the pros/cons of doing what I'm trying to do. My question is I'm trying to do something which OOP languages WILL allow you to do. Since most say JavaScript IS OOP, then how? – Jeach Jun 25 '12 at 19:18
  • Calm down. Yes I question the gain of having private fields in javascript. But the reason may be that I have javascript experience (but smalltalk, lisp, c, forth, java, pascal, or go too). I suggest you look at the way javascript is typically done and not try to force java into javascript. This being said this answer is valid and you can accept it if you really want to enforce privacy. – Denys Séguret Jun 25 '12 at 19:21
  • @Esailija: You can't imagine how long I've waited for a company to create a competitor to JavaScript. I guess it's of now surprise that it ends up being Google! I'm watching DART very closely and I can't wait till it's mature and ready because I will definitely use it. I'm sure it will have draw-backs since they are trying to be compatible with JS. But at least it we will be able to tool it in an IDE, which in itself a HUGE difference for companies that are serious about productivity. +1 for your suggestion. Note that I've used GWT and I'm not a big fan! – Jeach Jun 25 '12 at 19:23
  • 1
    @Jeach it is not widely accepted that information hiding is encapsulation (and therefore is not required for "OOP") see [javaworld](http://www.javaworld.com/javaworld/jw-05-2001/jw-0518-encapsulation.html) and [wiki](http://en.wikipedia.org/wiki/Encapsulation_(object-oriented_programming)) – Esailija Jun 25 '12 at 19:26
  • @dystroy: Apart from the fact that I have a Java background, what does Java have to do with this question? I'm trying to do something which is a requirement to OOP (encapsulation). I'm not trying to force JavaScript to any language, I just want to do what most programmers don't do. FYI (not that it really matters), but I also have assembler, C, C++, VB, Pascal and god knows what other language as experience. But that still doesn't change my need? – Jeach Jun 25 '12 at 19:27
  • @Esailija: Alright, what would say it's called then? So whatever we call for the time being, you do agree with me that being able to 'hide' members is an OOP concept? – Jeach Jun 25 '12 at 19:30
  • If you have a convention that private fields are not to be accessed externally, does it really matter that the engine enforces it ? That's the reason I suggest (in javascript) convention (like the _somevar naming). BTW I use this convention for private functions too. – Denys Séguret Jun 25 '12 at 19:31
  • 1
    @Jeach if we use distinct notions for information hiding (private stuff) and encapsulation (bundling data with methods that operate on that data), then javascript's object model fills all the fundamental concepts and features of OOP as described here http://en.wikipedia.org/wiki/Object-oriented_programming – Esailija Jun 25 '12 at 19:31
2
function Model() {
    var x = 3;
    var y = 'hello';
}

This creates a local (useless) variable x but you want a property of your newly created instance of Model.

Use

  function Model() {
    this.x = 3;
    this.y = 'hello';
}

Model.prototype.setY = function(myY) {
    y =  myY;
}

This doesn't change your property. Use

Model.prototype.setY = function(myY) {
    this.y =  myY;
}

Yes, javascript and java are very different. Prefer conventions (like calling your private fields starting with _) instead of trying to enforce privacy.

Denys Séguret
  • 372,613
  • 87
  • 782
  • 758
  • As stated in the question, this will expose the variables and the OP does not want to do that. (-1) – Platinum Azure Jun 25 '12 at 15:41
  • 1
    private property aren't a good practice of javascript. Javascript isn't java. – Denys Séguret Jun 25 '12 at 15:42
  • Agreed, but this does not answer the OP's question and so is a bad answer. Maybe the answer you *should* be posting is that private properties aren't a worthwhile practice in JavaScript. That would answer the OP's question. This does not, hence the -1. – Platinum Azure Jun 25 '12 at 17:08
  • Even if you add a prefix to your variables (such as your suggested '_'), you still have those idiots who will read the variable directly or worst will set it's value directly without going through the setter. Note that I down-voted the answer because it goes directly against what the question requested. Abstaining is sometimes the right thing to do. But I guess some just want to add content for the sake of increasing their scores. – Jeach Jun 25 '12 at 19:35
  • This answer fixed your code errors and suggested the way to do it that is the most adapted to javascript. I'm sorry you don't see it as helpful. – Denys Séguret Jun 25 '12 at 19:38
  • @Jeach I don't think information hiding solves the problem of idiots writing code at all ;p – Esailija Jun 25 '12 at 19:38
-2

You will need to use this

Model.prototype.getX = function() {
    return this.x;
}
Eruant
  • 1,816
  • 2
  • 14
  • 22