Reputation: 999
I have one problem with OOP in JavaScript. In following example, when newObj.position.x
is increased, newObj.x
is not increased, despite the fact that I wrote this.x = this.position.x
. Can you tell me why is that happening?
ClassOne = function( x, y )
{
this.x = x;
this.y = y;
};
ClassTwo = function( x, y, w, h )
{
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.position = new ClassOne( this.x, this.y );
this.x = this.position.x;
this.y = this.position.y;
}
var newObj = new ClassTwo( 10, 20, 30, 40 );
for ( var i = 0; i < 15; i++ )
{
newObj.position.x++;
console.log( newObj.x );
}
Result of the console.log is 10, 10, 10, 10, 10...
Upvotes: 0
Views: 754
Reputation: 51846
@ArunRedhu's answer has completely missed the point. This has nothing to do with newObj
and newObj.position
being separate objects, and everything to do with the fact that x
and y
are primitive values.
If you leave the code provided in the question the exact same except for replacing the values of x
and y
passed to the ClassTwo
constructor with non-primitive values like arrays, then the properties will reflect as expected, as shown at the bottom of this answer. This proves that the reason has nothing to do with the instantiation of separate objects in heap memory, and is simply a result of the type of parameter used.
The difference between primitives and non-primitives is that primitives are pass-by-value while non-primitives are pass-by-reference. Because of this, assigning a primitive to another variable or property causes the value to be copied rather than referenced.
ClassOne = function( x, y )
{
this.x = x;
this.y = y;
};
ClassTwo = function( x, y, w, h )
{
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.position = new ClassOne( this.x, this.y );
this.x = this.position.x;
this.y = this.position.y;
}
var newObj = new ClassTwo( [10], [20], 30, 40 );
for ( var i = 0; i < 15; i++ )
{
newObj.position.x[0]++;
console.log( newObj.x[0] );
}
Upvotes: 1
Reputation: 7136
newObj.position.x
and newObj.x
are 2 different values.
by doing
newObj.position.x++
You are increasing the x
field of the position
field of newObj
. Thus, the x
field of newObj
itself won't change, as the 2 fields are not linked.
One way to link them is by adding accessors.
With function objects
, you can create those like this :
ClassOne = function (x, y) {
this.x = x;
this.y = y;
};
ClassTwo = function (x, y, w, h) {
this.w = w;
this.h = h;
this.position = new ClassOne(x, y);
Object.defineProperty(this, 'x', {
get: function () { return this.position.x; },
set: function (newValue) { this.position.x = newValue; },
enumerable: true,
configurable: true
});
Object.defineProperty(this, 'y', {
get: function () { return this.position.y; },
set: function (newValue) { this.position.y = newValue; },
enumerable: true,
configurable: true
});
}
var newObj = new ClassTwo(10, 20, 30, 40);
for (var i = 0; i < 15; i++) {
newObj.position.x++;
console.log(newObj.x);
}
Edit: after seeing the other answers, I would like to say that I know using es6 classes is better (at least for readability), but I wanted to keep OP's functions.
Upvotes: 2
Reputation: 51846
Try using class
with getter and setter member methods so that it internally references the position
's values:
class One {
constructor (x, y) {
this.x = x
this.y = y
}
}
class Two {
constructor (x, y, w, h) {
this.w = w
this.h = h
this.position = new One(x, y)
}
get x () {
return this.position.x
}
set x (v) {
return this.position.x = v
}
get y () {
return this.position.y
}
set y (v) {
return this.position.y = v
}
}
let newObj = new Two(10, 20, 30, 40)
for (let i = 0; i < 15; i++) {
newObj.position.x++
console.log(newObj.x)
}
Upvotes: 2
Reputation: 138257
If you want both properties to always equal, you may use getters and setters ( and i will use the class syntax because i like it):
class Position {
constructor(x,y){
this.x = x;
this.y = y;
}
toString(){
return this.x+":"+this.y;
}
}
class Instance {
constructor(x,y,w,h){
this.w = w;
this.h = h;
this.position = new Position(x,y);
}
get x(){
return this.position.x;
}
set x(x){
this.position.x = x;
}
get y(){
return this.position.y;
}
set y(y){
this.position.y = y;
}
}
So one can do:
var player = new Instance(0,0,0,0);
player.x++;
player.position;//0:1
Upvotes: 2
Reputation: 1579
when you are creating an Object
with new
then it allocates the separate memory in the heap
. So the statement this.position = new ClassOne( this.x, this.y );
allocates the new memory for the this.position
and now this.position.x
and this.x
both belongs to separate memory. So when you changes the instance property for newObj.position.x
this would not get reflect to newObj.x
Upvotes: 2