0

I am having a problem with closures I think. I am really new to doing OOP JavaScript ONLY (I started this week...) but I have used JavaScript for little DOM manipulation stuff here or there and JQuery magic quite a few times. I am looking for a solution to my problem that does not involve changing my criteria because I want to try and finally learn proper JavaScript. My criteria is that I want the solution to be able to maintain my encapsulation and Java style publicly accessed private variables. My criteria also needs the solution to be able to teach me a bit about closures without repeating the examples at [thisPage]:How do JavaScript closures work? .

I have scoured the internet for a solution to my problem and the videos I have been finding, the books I red in school, the net pages I have red and the S.O. posts I have gone through have not yet shown me a good answer to why this is happening. That or I just really cannot grasp closures or whatever this problem is...

I have a class like this:

var Animal = {
    $name: "Blank",
    $age: -1,
    setName: function(n) {this.name=n;},
    setAge: function(a) {this.age=a;}
};

To which I then afterwards call...

Moose.prototype = Object.create(Animal);
Moose.prototype.constructor = Moose;
function Moose(newName, newAge) {
    this.setName(newName);
    this.setAge(newAge);
}

The this in this.setName() does what I want and finds Animal and adds a name to my moose without causing its Moose brethren to be also called "moosey moose mcDonkeybutt" or something....

I can successfully then, in console, create two 'Meese' or Mooses if you will and each has their own separated values. Like...

m1 = new Moose("MooseyMoose", 420);
m2 - new Moose("MooseMcTingles", 69);

And m1 wouldn't have the same values as m2 when inspected. Which is what I would expect from the other languages I have used over the years.... However this is where I get confused or at least glaring at my computer like, whoa, "what the douce?"

I want to add some kind of ability to gauge how each animal is moving over time. So I thought, hey, why not take this time to use the awesome power and simplicity of object literals to store this inside my class.... like so....

var Animal = {
    $name: "Blank",
    $age: -1,
    $position: {x:-1,y:-1},
    setName: function(n) {this.name=n;},
    setAge: function(a) {this.age=a;},
    getName: function() { return this.name; }
};

So I add in my accessor with a bit of extra load...

var Animal = {
    $name: "Blank",
    $age: -1,
    position: {x:-1,y:-1}, //I have tried $ and without
    setName: function(n) {this.name=n;},
    setAge: function(a) {this.age=a;},
    getName: function() { return this.name; },

    //New Accessor
    setPosition: function(newX, newY) {
        this.position.x = newX;
        this.position.y = newY;
    }
};

As I am sure the experienced programmers are reading at this point and saying... what an idiot. Problem is I have not read, searched or found the answer to have my AHH HA!! moment to this next part. If you already guessed what I am gonna have wrong you prolly should answer. Why on earth is this causing both m1 and m2 to have the same shared values on position now? Its not because its publicly declared I have tried with a private scope as well and it just makes it even harder for the this to find the correct prototype.

I have tried so SO many version of code on this block to try and figure out why I can't seem to store my position as a simple little object literal with easy access... I need all instances of Moose() to not be able to change each others position by using the setPosition() function above....

Also. I have tried converting it all to a function object rather than a var Object and I have also tried removing many combo's of this's that I knew weren't hitting the scope I need, however no luck yet. I have also tried removing the use of the .create() method and switched to the new keyword and also no luck.

EDIT: to the ppl replying.... like I said I have tried it all including adding getter setter methods to the position variable. It doesnt help at all it still shares the value....

Community
  • 1
  • 1
GoreDefex
  • 1,461
  • 2
  • 17
  • 41
  • Answerers, please skip reading the first three paragraphs... That is totally not relevant to the question. – thefourtheye Jul 02 '14 at 04:09
  • It's pretty annoying to see the function declaration for *Moose* after assigning to its prototype and other stuff. It's much easier to understand the code if it's written in a logical sequence. – RobG Jul 02 '14 at 05:14
  • @RobG yeah that should definitely be switched around. – John Jul 02 '14 at 05:16
  • Why does it matter this isnt a compiled language it is an interpereted language.... sequence means nothing. – GoreDefex Jul 02 '14 at 10:23
  • @thefourtheye did it hurt you to read two paragraphs? I was told to elaborare on my question as much as possible... those paragraphs let people know what answers NOT to bother giving me.... – GoreDefex Jul 02 '14 at 10:33
  • What is "*Java style publicly accessed private variables*"? Regardless, you probably should not, and use JavaScript style instead… – Bergi Jul 02 '14 at 10:53

1 Answers1

2

Lets take this step by step.

Do you have a member called position defined in Moose constructor?

No.

Then how the objects of Moose get position?

Through inheritance. Since Moose.prototype is set to be an Object of type Animal, when you say m1.position, JavaScript searches m1 for position and it moves up in the inheritance ladder to finding it in Moose.prototype Object. This searching is common for both m1 and m2. So, they both find the same Animal object in Moose.prototype. You can confirm that, like this

console.log(m1.position === m2.position);
# true

How do we get around this?

Simple. Don't define the member variables of the child objects in the Parent objects. Just move the definition of position to Moose constructor. Now, when the JavaScript searches for m1.position and m2.position, they both will have their own copy of position :-)

thefourtheye
  • 233,700
  • 52
  • 457
  • 497
  • Nice answer. OP, you may find this link helpful to explain prototypal inheritance http://javascriptissexy.com/javascript-prototype-in-plain-detailed-language/ – cortexlock Jul 02 '14 at 07:03
  • I know I can put it in the moose constructor but I just thought it looked like horrible code coming from java and c#. To repeat that variable creation when it can belong to all created from the inheritance seemed like I was repeating things too much. – GoreDefex Jul 02 '14 at 10:26
  • So in other words objects are passed by ref no matrer what even if they live in an instanced parent object being used by kids? I guess I'm not used to how javascript instances its objects such as Animal. – GoreDefex Jul 02 '14 at 10:31
  • No, if you want each instance to have its own position object, then you need to create a new position object for each instance. This is not "horrible code", this is just how it is done. – Bergi Jul 02 '14 at 10:59