I'm creating a bunch of objects and I want to use some of the objects in others, so I'm passing them in so I can update them later. I'd expect to hold a reference to each object, but if I pass an object before it's created, it stays undefined even after I create it. Here's the code:
this.screen = new BatchScreen(screenList);
this.fieldData = new FieldData(this.screen, this.nutrientData);
this.nutrientData = new NutrientData(this.screen, this.fieldData);
function FieldData(screen, nutrientData)
{
this.nutrientData = nutrientData;
}
this.fieldData.nutrientData is "undefined", which I don't understand as I thought this.fieldData holds a reference to this.nutrientData, which I create after it's assigned in this.fieldData.
I'm creating a bunch of objects and I want to use some of the objects in others, so I'm passing them in so I can update them later. I'd expect to hold a reference to each object, but if I pass an object before it's created, it stays undefined even after I create it. Here's the code:
this.screen = new BatchScreen(screenList);
this.fieldData = new FieldData(this.screen, this.nutrientData);
this.nutrientData = new NutrientData(this.screen, this.fieldData);
function FieldData(screen, nutrientData)
{
this.nutrientData = nutrientData;
}
this.fieldData.nutrientData is "undefined", which I don't understand as I thought this.fieldData holds a reference to this.nutrientData, which I create after it's assigned in this.fieldData.
Share Improve this question asked Jan 13, 2015 at 23:06 christian.stockchristian.stock 2013 silver badges15 bronze badges 8- possible duplicate of this inside function – PM 77-1 Commented Jan 13, 2015 at 23:09
- 3 How do you "pass an object before it's created"? – RobG Commented Jan 13, 2015 at 23:15
- @RobG - obviously you just use jQuery and delegate the dropping to a parent object. – adeneo Commented Jan 13, 2015 at 23:18
- 1 @adeneo—ah, must be part of the new crystal ball plugin. – RobG Commented Jan 13, 2015 at 23:21
- @RobG - I was being lazy, I could set this.nutrientData = null first, which would work in any other language, but to Javascript it's the same in this context. – christian.stock Commented Jan 13, 2015 at 23:24
3 Answers
Reset to default 4Short: you are not passing references.
Long: the evaluation strategy in JS is something called Call by sharing. It also is explained as "references passed by values".
What it means in details is that - in your
this.fieldData = new FieldData(this.screen, this.nutrientData);
statement the this.screen
holds a reference, so it's passed by value. And the this.nutrientData
holds nothing - so undefined
is passed.
Then when you run
this.nutrientData = new NutrientData(this.screen, this.fieldData);
statement the this.nutrientData
is being defined as a reference to a new object. But it's too late - we have already passed the undefined
in the FieldData
constructor.
So the best way to understand it - is to always think that the data is always passed by values, but sometimes those values keep references.
For your code to work as you expect the self.nutrientData
and others must be pointers, which JS does not support in any way.
The solution:
if you have 2 mutially dependent objects then you cannot have both in their own constructors. One of them just have to expose additional setter and accept the dependency through it.
Not an answer but a possible solution. You really need a getter but support isn't sufficiently widespread. If you have interdependent properties, you can implement a getter for one (or perhaps both for consistency) so you have:
this.screen = new BatchScreen(screenList);
// Don't bother passing this.nutrientData since you know it's not defined yet,
// pass in the object that you want the nutrientData property of
this.fieldData = new FieldData(this.screen, this);
this.nutrientData = new NutrientData(this.screen, this.fieldData);
// In here, use a function to return the property so its read when called,
// not when defined
function FieldData(screen, obj) {
this.getNutrientData = function () {return obj.nutrientData};
}
Then instead of:
var foo = someInstance.fieldData.nutrientData;
use:
var foo = someInstance.fieldData.getNutrientData();
But there seems to be a circular relationship between fieldData and nutrientData.
In this case, this.nutrientData
in the second line, is not being passed as a reference, since no reference to an object exists (at that point there is no this.nutrientData, so you are literally passing undefined
).
I'd guess you are also having scope issues with this
;
Try this (no pun intended):
var self = this;
this.screen = new BatchScreen(screenList);
this.fieldData = new FieldData(self.screen, new NutrientData(self.screen, self.fieldData));
// assumes that the nutrientData property exists from the object passed into FieldData
this.nutrientData = this.fieldData.nutrientData;
function FieldData(screen, nutrientData)
{
this.nutrientData = nutrientData;
}