0

I'm new to Javascript and was wondering how a public variable in a prototype can be modified.

function Thing (val)
{
    this.x = val;

    this.addToX = function (valIn)
    {
        this.x += valIn;
    };
}

function ChildThing ()
{
    this.y = 55;
}

ChildThing.prototype = new Thing(10);

var frank = new ChildThing();

console.log("out1: " + frank.x);

frank.addToX(10);

console.log("out2: " + frank.x);

This code takes the value in the prototype x which is 10 and adds 10 to it in the addToX function. The new x value is stored in the top level object rather than replacing the current x value in the prototype.

Is there a way to overwrite the existing x in the prototype or am I using Javascript wrong?

Epic Yeti
  • 71
  • 1
  • 11
  • 3
    Why are you trying to do this? https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem – candu Oct 01 '14 at 19:16
  • 1
    In general, you [shouldn't use `new` return values for prototypes](http://programmers.stackexchange.com/q/198267/51295). – apsillers Oct 01 '14 at 19:17
  • Okay, so I may have oversimplified my actual problem. It all comes down to my poor understanding of how inheritance should actually work in Javascript. The actual problem involves a render function being called and the x,y coordinates are taken from the prototype x,y. When attempting to alter these values, the child x,y values are updated and the values that are actually used to render always remain the same so the object is always drawn at the old location. – Epic Yeti Oct 01 '14 at 19:39
  • @EpicYeti You should have a look at my answer as well. – plalx Oct 01 '14 at 23:05

2 Answers2

1

That depends. What would be the point of altering x on the prototype? Generally you don't want to chang shared properties. But I imagine that there could be a use case (generating new id?).

As for the question: you can simply do:

this.addToX = function(valIn) {
    ChildThing.prototype.x += valIn;
};

Again I do not advice doing it.

EDIT You can make it without referencing the child by defining the prototype before setting it as a prototype, i.e.

var my_proto = new Thing(10);
ChildThing.prototype = my_proto;

and then

this.addToX = function(valIn) {
    my_proto.x += valIn;
};

Or you can even play with the singleton pattern.

Community
  • 1
  • 1
freakish
  • 54,167
  • 9
  • 132
  • 169
  • @plalx It's just an example. He can reference the prototype directly by defining it first `var new_proto = new Thing(10);`. And one more thing: unlike your answer mine answers the question. – freakish Oct 01 '14 at 20:34
  • Thanks for the help! Would using `this.__proto__.x += valIn;` be a bad idea? That seems to give similar results to what you suggested. – Epic Yeti Oct 01 '14 at 20:47
  • I don't see how my answer doesn't answer the question. It shows one way of achieving the exact same goal, which is sharing a primitive value which can be mutated across instances. Your answer works, but it's not very elegant and lacks flexibility in my opinion. – plalx Oct 01 '14 at 20:50
  • @EpicYeti `this.__proto__` is implementation depend. Might be unreliable AFAIK. – freakish Oct 01 '14 at 21:21
  • @EpicYeti You can use `Object.getPrototypeOf(this);` though. Note that there's a side effect to that: if you inherit one more time it might not return the prototype you originally wanted. – freakish Oct 01 '14 at 21:33
0

What you seem to be wanting is very similar to what static members are in classical languages. It's very misleading to call a method on an object instance and have that method modify the state of other objects outside of it's scope. Therefore, I believe you shounldn't be relying on prototypes at all for this behavior. Here's what you could do to mimic static members.

function SomeClass() {}

SomeClass.staticMember = 'initial value';
SomeClass.changeStaticMember = function (val) { this.staticMember = val; };

SomeClass.changeStaticMember('another value');

I believe the code above is less cryptic and better at communicating the behavior. However if you still want to share mutable values across instances through the prototype you could simply avoid writing the property directly as a primitive value, but rather wrap it within a mutable shared object like below. Note that the whole inheritance hierarchy will share the same x value.

//Mutable class to encapsulate the value of X
function XValue(val) {
  this.value = val;
}

XValue.prototype = {
  constructor: XValue,

  valueOf: function () { return this.value; },

  set: function (val) { this.value = val; },

  add: function (val) { this.value += val; }
};

function Thing(x) {
  this.x = x;
}

Thing.prototype = {
  constructor: Thing,

  _x: new XValue(), //shared mutable object representing the value of X

  get x() { return this._x.valueOf(); },

  set x(val) { this._x.set(val); },

  addToX: function (val) { this._x.add(val); }

};

function ChildThing() {
  Thing.call(this, 10); //call parent constructor
}

ChildThing.prototype = Object.create(Thing.prototype);


//helper for snippet
function log(text) {
    var span = document.createElement('span');
    span.innerHTML = text;
    document.body.appendChild(span);
    document.body.appendChild(document.createElement('br'));
}



var ct = new ChildThing();

ct.addToX(10);
log('ct.x → ' + ct.x);
log('Thing.prototype.x → ' + Thing.prototype.x);
plalx
  • 42,889
  • 6
  • 74
  • 90