I have an array of objects (this object also contains an array of it's own) I'm not sure why, but when I push some values onto the member array of one instance of the object in the array of objects it also seems to push onto the other member arrays on all other array of objects. I have provided my code below:
var ImageGroup = {
GroupName:"",
haz:[]
};
var ImageHandler = {
ImageGroupsArray:[],
image_process: function() {
//Calling the function here...
//Pushing the objects
this.ImageGroupsArray.push(Object.create(ImageGroup));
this.ImageGroupsArray.push(Object.create(ImageGroup));
//Assigning some values
this.ImageGroupsArray[0].haz.push("Dog");
this.ImageGroupsArray[1].haz.push("Cat");
//Should output array with only 'Dog' in it
console.log(this.ImageGroupsArray[0].haz);
//Should output array with only 'Cat' in it
console.log(this.ImageGroupsArray[1].haz);
//Instead, both of these output ["Dog","Cat"]
//this.ImageGroupsArray[1].haz and this.ImageGroupsArray[0].haz point to same 'haz' array??
}
}
This doesn't happen when I try to set the GroupName the same way. What am I doing wrong? Thanks for any help in advance!
This code:
var ImageGroup = {
GroupName:"",
haz:[]
};
creates a single object in memory. This code:
this.ImageGroupsArray.push(Object.create(ImageGroup));
this.ImageGroupsArray.push(Object.create(ImageGroup));
creates two new objects (pushing each onto the ImageGroupsArray). Both of these objects have the same ImageGroup object as their prototype. Just knowing how prototypes work will help you a lot on this one. But basically, this code:
this.ImageGroupsArray[0].haz.push("Dog");
this.ImageGroupsArray[1].haz.push("Cat");
looks for the haz property on each of those Object.create()ed objects. When it can't find it, it looks up the prototype chain and finds it on the parent object (which is the same object in both cases). Any modifications made to this one object will, of course, show up in all places where this object is referenced (so in both the objects you pushed to ImageGroupsArray).
The correct approach is to declare ImageGroup as a function that defines its properties:
var ImageGroup = function() {
this.GroupName = '';
this.haz = [];
}
then use the new keyword, instead of Object.create():
this.ImageGroupsArray.push(new ImageGroup());
this.ImageGroupsArray.push(new ImageGroup());
Cheeers.
You are pushing same object ImageGroup in ImageGroupArray and so it is actually making effect in the same object which is defined globally.
Try this instead
function getImageGroup()
{
var imageGroup = new Object();
imageGroup.GroupName = "";
imageGroup.haz = [];
return imageGroup;
}
this.ImageGroupsArray.push(getImageGroup());
this.ImageGroupsArray.push(getImageGroup());
Working Fiddle
It seems you are referencing the same ImageGroup object twice.
The 'groupName' property gets overwritten, but the array can grow endlessly :-)
Try:
var ImageGroup1 = { GroupName:"foo", haz:[]};
var ImageGroup2 = { GroupName:"bar", haz:[]};
So you get two different objects in stead of two references to the same object.
Related
In this code... mapObj.fetchTimeObjs should NOT change right?!?!
Somehow mapObj.fetchTimeObjs gets changed when this function is run:
function clockErasePast(){
var now = new Date().getTime();
var tmpFetchTimeObjs = [];
for(var i =0; i<mapObj.fetchTimeObjs.length; i++){
tmpFetchTimeObjs.push(mapObj.fetchTimeObjs[i]);
if(mapObj.fetchTimeObjs[i].start < now){tmpFetchTimeObjs[i].start = now;}
}
return tmpFetchTimeObjs;
}
tmpFetchTimeObjs[i]
will contain only reference to the mapObj.fetchTimeObjs[i].
If you will change tmpFetchTimeObjs[i], the mapObj.fetchTimeObjs[i] will be changed, because you will have only one object which has two references. And if it will changed from one reference, it will be changed for the second reference too.
Let's consider an object which has two references. Here I change the object from one reference, and get the update for the second reference, because they refer to the same object.
var objA = { name: 'Bob', age: 25};
var objB = objA;
objB.age = 30;
console.log(objA.age);
To get independent object you need to create them. You can use Object.assign() function, which will copy any enumerable properties from into the destination(first parameter) object and returns it.
You can create with
var obj = Object.assign({}, mapObj.fetchTimeObjs[i]);
tmpFetchTimeObjs.push(obj);
The objects you push to the new array, are the same as the original array has, so if you mutate them, that mutation is visible to both arrays. This is what is called doing a shallow copy.
You could make a copy at one deeper level, where you would also create new objects and copy the original object's properties (like start) into those new objects. This you can easily do with Object.assign:
tmpFetchTimeObjs.push(Object.assign({}, mapObj.fetchTimeObjs[i]));
If these objects themselves have nested objects, then the problem you had would occur at deeper levels. If this is an issue, then you should look to deep clone solutions, like provided in this Q&A.
You need to clone the TimeObjs, since variables only keep the reference to the TimeObjs. We don't know the structure of your TimeObjs, so if the TimeObjs doesn't contain other objects, Object.assign() will work, otherwise maybe you need a deep clone method, such as jQuery.extend().
Newbie here...be nice.
I have an empty object that will get pushed into an array.
listView = {};
I add properties to it.
listView.code = code;
listView.description = description;
I push the results object into an array.
listy.push(listView);
Each time I enter a new selection in step #2 it overwrites the object instead of adding the new object properties to the array. It also increments the index by one, so it just repeats...
[{"code":"I77.812","description":"Thoracoabdominal Aortic Ectasia"}]
[{"code":"I77.811","description":"Abdominal Aortic Ectasia"},{"code":"I77.811","description":"Abdominal Aortic Ectasia"}]
[{"code":"I06.1","description":"Rheumatic aortic insufficiency"},{"code":"I06.1","description":"Rheumatic aortic insufficiency"},{"code":"I06.1","description":"Rheumatic aortic insufficiency"}]
The array should contain three different objects. But instead it has three copies of the newly added one...
How should I be adding the new choice objects so that they don't get overwritten?
You are always adding a reference to the same object, and changing that same object, instead of adding new objects. See this:
var a = [];
var o = {};
for (var i = 0; i < 5; i++) {
o.id = i;
a.push(o);
}
a
// => [{"id":4},{"id":4},{"id":4},{"id":4},{"id":4}]
But
var a = [];
for (var i = 0; i < 5; i++) {
var o = {};
o.id = i;
a.push(o);
}
a
// => [{"id":0},{"id":1},{"id":2},{"id":3},{"id":4}]
The difference is, the second code always makes a new object that is distinct from all other objects already in the array.
As a metaphor, imagine a theatre director in casting. He turns to an actor, says "You... you'll be Romeo.". Then he looks at the same actor, says "You... you'll be Mercutio. Here, Mercutio, take this sword. Romeo... who told you to get a sword?!?" completely failing to realise that, if Romeo and Mercutio are the same person, if one of them picks up a sword, the other does it too.
Seeing as you declared yourself a 'newbie' i figured i'd take a bit more time explaining. When you push an object to an array, you don't copy the object. You just tell the array where to find the object (a reference). If you push the same object 3 times, the array just has 3 indexes at which it finds the same object. There's several ways around this, the easiest being that you declare the variable inside the loop
for (var i=0;i<3;i++){
var listView = {};
listView.id = i;
listy.push(listView);
}
This way listView is a different reference each time. The other way is to create a new object when you push
listy.push({id:listView.id, description:listView.description});
which works because simple variables are 'copied' into the array and not referenced.
your assignment of the properties of an object are simply replacing the existing properties. wh en you push the object in the array by name, you are push a reference to the object and not a value. This is why all the elements in the array are the same. You need to create a new object every time you push. Something like this should work for you.
listy.push({code:code, description:description});
try this :
listy.push({
code:listView.code,
description : listView.description
})
In my code I have used pass by value.
In your code , you are using Objects which are passed by reference .
You are adding same reference again and again so at the end you will get an array having all the values of same object .
To understand more about pass by value and pass by reference you can reffer this link :
Pass Variables by Reference in Javascript
I have found a behavior I did not expect when trying to use a loop in order to change the value set for a property in an object.
Basically, I declare my object outside the loop.
Then I loop on an array of numeric values, which values are used to update the object property.
Inside the loop, I store the current object state inside an external array.
The result is that instead of having an array containing a series of objects with different numeric values, I end up having the same numeric values in each object stored.
Here is the fiddle http://jsfiddle.net/fAypL/1/
jQuery(function(){
var object_container = [];
var numeric_values = [1, 2 , 3, 4];
var my_object = {};
jQuery.each(numeric_values, function(index, value){
my_object['value'] = value;
object_container.push(my_object);
});
jQuery.each(object_container, function(index, value){
jQuery('#content').prepend(value['value']);
});
});
I would expect to get 1 2 3 4 as values stored in each object, however, what I get is 4 4 4 4, which does not make sense to me.
Any hint on this behavior is more than welcome, thanks
When your code calls .push() and passes my_object, what's being passed is a reference to the object. No copy is made.
Thus, you've pushed four references to the exact same object into the array.
JavaScript objects always participate in expressions in the form of references. There's no other way to deal with objects. Thus when you create a variable, and set its value to be an object, you're really setting its value to be a reference to the object. Same with parameter passing, and anywhere else an object can appear in an expression.
In this case, you can create new objects pretty easily; just dispense with my_object and push a fresh one on each iteration:
object_container.push( { value: value } );
You are not creating a new object each time around the loop - you are just updating the same existing object and pushing references of that to the object array. To create a new object you want to do something like:
my_object = { 'value': value };
object_container.push(my_object);
In this case you now will get something more like what you were looking for. See the updated fiddle here: http://jsfiddle.net/fAypL/2/.
Best of luck!
One more thought (Clone!) - If you are really tied to using the same object each time, just clone the object before you add to the array. There is a great solution for that here.
You are using jQuery so if what you want is to merge without effecting the original look at :
var both_obj = $.extend( {}, default_obj , adding_obj );
This will leave your original object changed, also good to use for a copy.
jquery docs - extend()
An alternate version is to use an object with a constructor and the new keyword:
var object_container = [];
var numeric_values = [1, 2 , 3, 4];
function MyObject(value)
{
this.value = value;
}
jQuery.each(numeric_values, function(index, value){
object_container.push(new MyObject(value));
});
jQuery.each(object_container, function(index, value){
jQuery('#content').prepend(value['value']);
});
Fiddle
I have a function within an object constructor that is altering all objects created by that constructor. I'm not sure why. Could someone please take a look at my code and tell me what I'm missing?
A quick description of what is going on:
Warning! It might be easier to just read through the code than try to make sense of my description
I have created two new Arrays. The first one called foos, which will be an array of foo objects each one containing an array of bar objects. The second is called bars which is an array of all bar objects that are available to be added to the foos.foo.bars arrays.
When a new foo object is created using the foo object constructor it is given two arguments(aBars,bBars). aBars is an array of all bar objects to be included in the foo object. bBars is an array of all included bar objects that are considered 'special' in some way. Within the constructor there is a function that runs through every object in the bars array and if it's name value matches that of a string in the aBars argument then it is added to foo.bars array. If it's name value matches a string in the bBars argument it then has it's property bBar set to true, otherwise it's set to false.
The issue I'm having is that on the second foo object constructor when a bar object has bBar set to true or false it also changes that value in that object in all other foo.bars objects.
I realize that this is probably hard to follow. Sorry about that, it's the end of the day.
Found my own answer!
I just realized what the issue is. foos[0].bars[4] and foos[1].bars[3] are not separate objects, they are simply two different variables pointing to the same object. So when one is changed the change shows up on both. Wow, I can't believe I just spent so much time working on this when the answer was a basic fact about how javascript works that I learned back when I first started.
Ok, the new question:
How can I change this code to create duplicates of the objects instead of just pointing at the originals? This is not something I've ever had to do before.
Thanks
jsfiddle
JS:
var foos = new Array();
var bars = new Array();
function foo(aBars,bBars) {
var $this = this;
this.aBars = aBars;
this.bars = new Array();
bars.forEach(function(e,i) {
if ($this.aBars.lastIndexOf(e.barName) > -1) {
$this.bars.push(e);
if (bBars.lastIndexOf(e.barName) > -1) {
$this.bars[$this.bars.length-1].bBar = true;
} else {
$this.bars[$this.bars.length-1].bBar = false;
}
}
});
}
function bar(name) {
this.barName = name;
}
bars.push(new bar('l'));
bars.push(new bar('m'));
bars.push(new bar('n'));
bars.push(new bar('o'));
bars.push(new bar('p'));
foos.push(new foo(['l','m','n','o','p'],['n','p']));
foos.push(new foo(['l','n','o'],['n','o']));
console.log(foos);
The only way to achieve that would be to replace this line
$this.bars.push(e);
in your 'foo'-constructor with this one:
$this.bars.push(new bar(e.barName));
Cloning objects in javascript is only possible by copying their properties.
I am a bit confused at this point on what is an object, what is an array, and what is a JSON. Can someone explain the differences in syntax between the two? and how to add items to each, how to merge each type, and such? I am trying to get this function to take the new information from a JSON object (I think) and merge it with some new information. This information will then be passed to a PHP script to be processed.
Here is the console output:
{"public":{"0":["el29t7","3bmGDy"]}}
{"public":"[object Object][object Object]"}
Here is the JS I am using:
/* Helper function to clean up any current data we have stored */
function insertSerializedData(ids, type) {
// Get anything in the current field
current_data = $('#changes').val();
if (!current_data) {
var data = {};
data[index++] = ids;
var final_data = {};
final_data[type] = data;
$('#changes').val(JSON.stringify(final_data));
} else {
current_data = JSON.parse(current_data);
var data = {};
data[index++] = ids;
// Does the index exist?
if (type in current_data) {
var temp_data = current_data[type];
current_data[type] = temp_data + data;
} else {
current_data[type] = data;
}
//var extra_data = {};
//extra_data[type] = data;
//$.merge(current_data, extra_data);
$('#changes').val(JSON.stringify(current_data));
}
console.log($('#changes').val());
}
The idea is if the key (public, or whatever other ones) doesn't exist yet, then to make it point to an array of arrays. If it does exist though, then that of array of arrays need to be merged with a new array. For instance:
If I have
{"public":{"0":["el29t7","3bmGDy"]}}
and I want to merge it with
["aj19vA", "jO71Ba"]
then final result would be:
{"public":{"0":["el29t7","3bmGDy"], "1":["aj19vA", "jO71Ba"]}}
How can i go about doing this? Thanks
Excellent two-part question. Overall, the second question is non-trivial because of the complexity of the first.
Question 1:
what is an object, what is an array, and what is a JSON. Can someone
explain the differences in syntax between the two?
Question 2:
and how to add items to each,
Question 3:
how to merge each type, and such?
Answer 1:
This is a common stumbling point because, JavaScript is more flexible than one might initially expect. Here is the curve.
In JavaScript everything is an object.
So here is the code for each:
//What is an object?
var obj = { };
var obj2 = { member:"value", myFunction:function(){} }
Above is an empty object. Then another object with a variable and a function.
They are called object-literals.
//What is an array
var array1 = [ ] ;
var array2 = [0,1,2,3,4];
Above is an empty array. Then another array with five Integers.
Here is the curve that causes confusion.
//Get elements from each of the prior examples.
var x = obj2["member"];
var y = array2[1];
What??? Both Object and Array are accessing values with a bracket?
This is because both are objects. This turns out to be a nice flexibility for writing advanced code. Arrays are objects.
//What is JSON?
JSON stands for JavaScript Object Notiation. As you might have guessed. Everything is an object... It is also an { }; But it is different because - it is used to transfer data to - and - from JavaScript, not actually used (commonly) in JavaScript. It is a file transfer format.
var JSONObject = {"member":"value"};
The only difference to the prior example is quotes. Essentially we are wrapping the object literal as a string so that it can be transferred to a server, or back, and it can be reinterpreted, very easily. Better than XML - because it does not have to be custom-parsed. Just call, stringify() or ParseJSON(). Google it. The point is... JSON can be converted into an object-literal JS object, and JS object-literals can be converted into JSON, for transfer to a server or a CouchDB database, for example.
Sorry for the tangent.
Answer 2:
How to add an item to each? Here is where the curve stops being a nuisance, and starts being awesome! Because everything is an object, it is all just about the same.
//Add to an object
var obj {member1:"stringvalue"}
obj.member2 = "addme"; //That is it!
//Add to an array
var array1 [1,2,3,4,5];
array1[0] = "addme";
array[6] = null;
//We shouldn't mix strings, integers, and nulls in arrays, but this isn't a best-practice tutorial.
Remember the JS object syntax and you may start to see a whole new flexible world of objects open up. But it may take a bit.
Answer 3: Ah, yeah... how to merge.
There are seriously (very many) ways to merge two arrays. It depends on exactly what you need. Sorted, Duplicated, Concatenated... there are a few.
Here is the answer!
UPDATE: How to make a beautiful multiple dimensional array.
//Multiple Dimension Array
var array1 = [1,2,3];
var array2 = [3,4];
var arraysinArray = [array1,array2]; //That is it!
Here is the curve again, this could be in an object:
var obj{
array1:[1,2,3],
array2:[3,4]
}
JavaScript is powerful stuff, stick with it; it gets good. : )
Hope that helps,
All the best!
Nash
In this case, think of a JavaScript's object literal {} as being like PHP's associative array.
Given that, an "array of arrays" actually looks like this (using your above desired output):
{public: [["el29t7","3bmGDy"], ["aj19vA", "jO71Ba"]]}
So here we have an object literal with a single property named "public" whose value is a 2-dimensional array.
If we assign the above to a variable we can then push another array onto "public" like this:
var current_data = {public: [["el29t7","3bmGDy"], ["aj19vA", "jO71Ba"]]};
// Using direct property access
current_data.public.push(["t9t9t9", "r4r4r4"]);
// Or using bracket notation
current_data["public"].push(["w2w2w2", "e0e0e0"]);
current_data's value is now:
{public: [
["el29t7","3bmGDy"],
["aj19vA", "jO71Ba"],
["t9t9t9", "r4r4r4"],
["w2w2w2", "e0e0e0"]
]}
So now "public" is an array whose length is 4.
current_data.public[0]; // ["el29t7","3bmGDy"]
current_data.public[1]; // ["aj19vA", "jO71Ba"]
current_data.public[2]; // ["t9t9t9", "r4r4r4"]
current_data.public[3]; // ["w2w2w2", "e0e0e0"]
MDN has very good documentation on Array for insight on other functions you might need.
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array
First is an object, that contains array, second is an array.
DEMO showing display output http://jsfiddle.net/GjQCV/
var object={"public":{"0":["el29t7","3bmGDy"]}};
var arr=["aj19vA", "jO71Ba"] ;
/* use object notation to add new property and value which is the array*/
object.public[1]=arr;
It'd be much more natural if {"0": ...} were a true array rather than an object, but anyway:
function maxKey(b) {
var max;
for( var key in b )
var max = key;
return max;
}
function merge(a,b) {
for( var key in a ) {
b[key] = b[key] ? (b[key][maxKey(b)+1]=a[key], b[key]) : a[key];
}
return b;
}
Note that this assumes you would insert at the next integer index
Arrays are a particular kind of Javascript object
JSON is a way of representing Javascript objects (and as such can represent arrays and more)
Objects are much more general, and can be simple objects that can be represented as JSON, or can contain functions and prototypes.
So, this is not an array of arrays (you would access items using JSON notation like myobj["0"]):
{"0":["el29t7","3bmGDy"], "1":["aj19vA", "jO71Ba"]}
This is an array of arrays, which means you can use the push method to add an item, and access items using array notation like myobj[0]:
[ ["el29t7","3bmGDy"], ["aj19vA", "jO71Ba"] ]
It seems like the structure you want is something like this:
var myobj = { "public": [ ["key", "value"], ["key", "value"] ] }
Then if you want to add/merge new items, you'd write this:
if (myobj["public"] != null) {
myobj["public"].push(["newkey", "newval"]);
} else {
myobj["public"] = ["newkey", "newval"];
}