Javascript pushing objects into array changes entire array - javascript

I'm using a specific game making framework but I think the question applies to javascript
I was trying to make a narration script so the player can see "The orc hits you." at the bottom of his screen. I wanted to show the last 4 messages at one time and possibly allow the player to look back to see 30-50 messages in a log if they want. To do this I set up and object and an array to push the objects into.
So I set up some variables like this initially...
servermessage: {"color1":"yellow", "color2":"white", "message1":"", "message2":""},
servermessagelist: new Array(),
and when I use this command (below) multiple times with different data called by an event by manipulating servermessage.color1 ... .message1 etc...
servermessagelist.push(servermessage)
it overwrites the entire array with copies of that data... any idea why or what I can do about it.
So if I push color1 "RED" and message1 "Rover".. the data is correct then if I push
color1"yellow" and message1 "Bus" the data is two copies of .color1:"yellow" .message1:"Bus"

When you push servermessage into servermessagelist you're really (more or less) pushing a reference to that object. So any changes made to servermessage are reflected everywhere you have a reference to it. It sounds like what you want to do is push a clone of the object into the list.
Declare a function as follows:
function cloneMessage(servermessage) {
var clone ={};
for( var key in servermessage ){
if(servermessage.hasOwnProperty(key)) //ensure not adding inherited props
clone[key]=servermessage[key];
}
return clone;
}
Then everytime you want to push a message into the list do:
servermessagelist.push( cloneMessage(servermessage) );

When you add the object to the array, it's only a reference to the object that is added. The object is not copied by adding it to the array. So, when you later change the object and add it to the array again, you just have an array with several references to the same object.
Create a new object for each addition to the array:
servermessage = {"color1":"yellow", "color2":"white", "message1":"", "message2":""};
servermessagelist.push(servermessage);
servermessage = {"color1":"green", "color2":"red", "message1":"", "message2":"nice work"};
servermessagelist.push(servermessage);

There are two ways to use deep copy the object before pushing it into the array.
1. create new object by object method and then push it.
servermessagelist = [];
servermessagelist.push(Object.assign({}, servermessage));
Create an new reference of object by JSON stringigy method and push it with parse method.
servermessagelist = [];
servermessagelist.push(JSON.parse(JSON.stringify(servermessage));
This method is useful for nested objects.

servermessagelist: new Array() empties the array every time it's executed. Only execute that code once when you originally initialize the array.

I also had same issue. I had bit complex object that I was pushing in to the array. What I did; I Convert JSON object as String using JSON.stringify() and push in to the Array.
When it is returning from the array I just convert that String to JSON object using JSON.parse().
This is working fine for me though it is bit far more round solution.
Post here If you guys having alternative options

I do not know why a JSON way of doing this has not been suggested yet.
You can first stringify the object and then parse it again to get a copy of the object.
let uniqueArr = [];
let referencesArr = [];
let obj = {a: 1, b:2};
uniqueArr.push(JSON.parse(JSON.stringify(obj)));
referencesArr.push(obj);
obj.a = 3;
obj.c = 5;
uniqueArr.push(JSON.parse(JSON.stringify(obj)));
referencesArr.push(obj);
//You can see the differences in the console logs
console.log(uniqueArr);
console.log(referencesArr);

This solution also work on the object containing nested keys.
Before pushing, stringify the obj by
JSON.stringify(obj)
And when you are using, parse by
JSON.parse(obj);

As mentioned multiple times above, the easiest way of doing this would be making it a string and converting it back to JSON Object.
this.<JSONObjectArray>.push(JSON.parse(JSON.stringify(<JSONObject>)));
Works like a charm.

Related

Javascript object properties with same values experience the same changes when they shouldn't (splice)

I'm not sure if this is a bug or if I have a complete misunderstanding of Javascript, but this is what happens:
I take an object with two arrays inside it, one representing the current queue of IDs and another representing the total queue of IDs (hypothetical situation)
var mainObject = {
object1:[],
object2:[]
};
In a function, we set the two property arrays to the same variable which holds the array needed before we can start processing the queue.
var randomVar = [1,2,3,4];
mainObject.object1 = randomVar;
mainObject.object2 = randomVar;
Now we want to make use of the splice method to remove the first index from object1 while keeping it on object two.
mainObject.object1.splice(0,1);
The result of the object is now as follows:
mainObject = {
object1:[2,3,4],
object2:[2,3,4]
};
meaning that both of the properties were spliced when we only asked Javascript to run it once.
See JS Fiddle for live example:
https://jsfiddle.net/ypow6y8g/
Is there something I'm missing or is this just another night spent with loose JS?
You have one array, and two variables whose value is a reference to that array. When you modify the value of one of those variables, you modify the other one as it's the same.
If you want your arrays to be independent, clone one:
var randomVar = [1,2,3,4];
mainObject.object1 = randomVar;
mainObject.object2 = randomVar.slice(); // slice returns a new array

Cloning and manipulating nested object using forEach, map, or filter without modifying original object

I'm trying to get a handle on using .map, .filter to clone and modify a big nested JSON object based on a deeply nested property. With the below code, the original data and the filtered data both end up getting modified, but I'm trying to leave the original data intact. What I'm hoping to do is have the deeply nested concerns array emptied in the final filtered object for a given id, leaving the original data as the original complete data set.
var data {...};
var dataFilter = function dataBuild(data) {
var newData = data;
newData.service_requests = newData.service_requests.map((request) => {
request.concerns = request.concerns.filter((concern) => {
return concern.building_id == 2
});
return request;
});
return newData;
};
var filtered = dataFilter(data);
Here's a fiddle with what I'm trying to do with the full object in there.
http://jsbin.com/doyoqinoxo/edit?js,console
When you do:
var newData = data;
you are simply making a second reference to the same object, so:
newData.service_requests = ...
overwrites the value in data.service_requests.
It seems you want newData to be a copy of data, not a reference to the same object. There are plenty of posts here on how to copy a nested object (a so–called deep copy), e.g. What is the most efficient way to clone an object?, but please ignore the accepted answer unless you are using jQuery. Use one of the other answers, like this one.
JSIterator .map() creates the new array with the same number of elements or does not change the original array. There might be the problem with referencing if there is object inside the array as it copies the same reference, so, when you are making any changes on the property of the object it will change the original value of the element which holds the same reference.
The solution would be to copy the object, well, array.Splice() and [...array](spread Operator) would not help in this case, you can use JavaScript Utility library like Loadash or just use below mention code:
const newList = JSON.parse(JSON.stringify(orinalArr))

How to access object of array?

I am new to jquery and trying something and got stuck at it,
My problem is i have object with array in it i am not able to find the way to access that array from the object
//My object is shown in debugging time is as below
cache:object
0001-:Array[2]
0:value1,
1:value2
_prto_:object
and i want to access the value1 and value2 from the 0001- array from that object is there way to access that array. Any help would be great. I know with $.each i can loop through it and and then again access the array but is there any other way to do it.
You can access it like, and keep in mind that you should use bracket notation in this context, since your keys having a starting character as a number.
cache['0001-'][0] //first element on that array
cache['0001-'][1] //second element
A workaround for your new requirement,
var cache = {'0001-' : [0,1]};
var xKeys = Object.keys(cache);
console.log(xObj[xKeys[0]][0]);
console.log(xObj[xKeys[0]][1]);

how to save an array in an object at runtime in javascript

I want to save an array in an object in runtime through a loop.
For example, I take an input in an array inp=[2, 7, 20, 15, 19] and I want to save it in an obj={0:2, 1:7, 2:20, 3:15, 4:19}. But, at runtime such that I have a
for(i=0;i<inp.length;i++)
{ save each element of array into the respective object element }
The problem is that I have to save arrays of different lengths, these array come from taking an input from user.
I am also sorting the object afterwards and returning the indices in another array in my code. I am stuck only at how to save an array in an object during runtime. I searched a lot for a clue to get started but, I could not find anything.
Autoassign: (credit: am not i am)
var obj = inp.slice();
Manual Assignment:
var obj = {};
for(var i=0, n=inp.length; i<n; i++)
obj[i]=inp[i];
Though an Array is technically a subclass of an Object in JavaScript, the only thing that is really happening in going from an Array to an Object, is that you're losing the native methods (indexOf,concat,reverse,etc) that are created during the array's construction.
Array is already an object
If you do some experiments, you would find out:
typeof([]) //<--retruns "object"

Convert a javascript associative array into json object using stringify and vice versa

I have a javascript associative array like one below
var my_cars= new Array()
my_cars["cool"]="Mustang";
my_cars["family"]="Station Wagon";
my_cars["big"]="SUV";
I want to convert it using Stringify to json object. I want to know after conversion how the json object will look like.
Also when i have this object How I can convert it back to associative array again.
First of all, by making my_cars an array and stringifying it, you don't get what you expect.
var my_cars= new Array()
my_cars["cool"]="Mustang";
my_cars["family"]="Station Wagon";
my_cars["big"]="SUV";
alert(JSON.stringify(my_cars));
This alerts [].
What you want is to start with {}:
var my_cars= {};
my_cars["cool"]="Mustang";
my_cars["family"]="Station Wagon";
my_cars["big"]="SUV";
alert(JSON.stringify(my_cars));
This alerts
{"cool":"Mustang","family":"Station Wagon","big":"SUV"}
To get your object back from the string, use JSON.parse().
var s = JSON.stringify(my_cars);
var c = JSON.parse(s);
alert(c.cool);
This alerts "Mustang".
See http://jsfiddle.net/Y2De9/
No,But the user want to use array not json.
Normal JavaScript arrays are designed to hold data with numeric indexes. You can stuff named keys on to them (and this can be useful when you want to store metadata about an array which holds normal, ordered, numerically indexed data), but that isn't what they are designed for. The JSON array data type cannot have named keys on an array.
If you want named keys, use an Object, not an Array.
*source
var test = []; // Object
test[0] = 'test'; //this will be stringified
Now if you want key value pair inside the array
test[1] = {}; // Array
test[1]['b']='item';
var json = JSON.stringify(test);
output
"["test",{"b":"item"}]"
so you can use an index with array,so alternatively
var my_cars= [];
my_cars[0]={};
my_cars[0]["cool"]="Mustang";
my_cars[1]={};
my_cars[1]["family"]="Station Wagon";
my_cars[2]={};
my_cars[2]["big"]="SUV";
console.log(JSON.stringify(my_cars));
Output
"[{"cool":"Mustang"},{"family":"Station Wagon"},{"big":"SUV"}]"
Moving my comment into an answer so I can show you a code example.
These types of array are no-no's in javascript. You should ONLY use an object for non-numeric keys like this. Array indexes should be numbers. Javascript objects can use arbitrary values for keys (like in your example). Arrays happen to "appear" to work because Arrays themselves are objects, but you will not find normal Array methods will work on them. For example, look at this code example.
var my_cars= new Array()
my_cars["cool"]="Mustang";
my_cars["family"]="Station Wagon";
my_cars["big"]="SUV";
alert(my_cars.length); // alerts 0
You have only added properties to the underlying object, not actually added elements to the Array. You should use an Object for this, not an Array. Javascript does not actually have an Associative Array. It has an Object who's properties can often be used like one would use an Associate Array in other languages. But, it's an Object, not an Array.
"JavaScript does not support arrays with named indexes"
The most close state to an associative array is an array with entries converted to properties (as in your case), so I provide a solution for this exact case.
The fun thing is that Chrome's console makes it feel like an associative array: ["cool":"Mustang", "family":"Station Wagon", "big":"SUV"] (Check with F12)
NOTE: open browser's console before running the snippet
var my_cars= new Array()
my_cars["cool"]="Mustang";
my_cars["family"]="Station Wagon";
my_cars["big"]="SUV";
let toAssociative=(keys, values)=>
values.reduce((acc, cv)=>{
acc[acc.shift()]=cv
return acc;
}, keys)
let fromAssociative = (assArr)=>({...assArr})
let serialized = JSON.stringify(fromAssociative(my_cars))
let o = JSON.parse(serialized)
let restored = toAssociative(Object.keys(o) , Object.values(o))
//NOTE: Look at the browser's console before executing (not SO console)
console.log("orig:",my_cars)
//[cool: "Mustang", family: "Station Wagon", big: "SUV"]
console.log("serialized:",serialized)
//{"cool":"Mustang","family":"Station Wagon","big":"SUV"}
console.log("restored:",restored) //NOTE: look at the browser's console (F12)
//[cool: "Mustang", family: "Station Wagon", big: "SUV"]
If for some reason you cannot convert your array into object, for instance you are working on a big framework or legacy code that you dont want to touch and your job is only to add som feature which requires JSON API use, you should consider using JSON.stringify(json,function(k,v){}) version of the API.
In the function you can now decide what to do with value of key is of a specific type.

Categories

Resources