Strange behavior in jQuery loop with arrays - javascript

I am having an issue with the following code:
var samount = [{value:100, name:'USD'},
{value:200, name:'USD'},
{value:100, name:'USD'}];
var object1 = new Array;
objects1 = samount;
var categories1 = new Array();
var groupedObjects1 = [];
var output1 = '';
var i = 0;
console.log(samount);
_.each(objects1,function(obj){
var existingObj;
if($.inArray(obj.currency,categories1) >= 0) {
existingObj = _.find(objects1,function(o){return o.currency === obj.currency;});
existingObj.value += obj.value;
} else {
groupedObjects1[i] = obj;
categories1[i] = obj.currency;
i++;
}
});
console.log(samount);
console.log(groupedObjects1);
The problem is that I do not want that samount variable to change after looping, so I have done this:
var object1 = new Array;
objects1 = samount;
The goal of this script is to sum up all values from the same currencies, but still to not mess with the initial array.
But it still changes the initial Array. Could anyone help me with this error?

Copy the array with slice
var objects1 = samount.slice(0);
Arrays and object are passed by "reference" (not really, but doesn't matter here), so when assigning an array to a new variable, all you get is a reference to the same array, not a new array.

You need to deep copy the initial array instead of affecting it.
var samount = [{value:100, name:'USD'},
{value:200, name:'USD'},
{value:100, name:'USD'}];
var object1 = $.extend(true, [], samount);
You were doing an affectation (i.e. 2 variables pointing to the same object) where you needed a copy (2 variables pointing to 2 different objects)

The problem is you're not creating a copy with
objects1 = samount
In most OO languages, you can only copy primitive types so int, strings characters etc, but not objects.
This is somewhat similar in javascript in the sense that {} is an object, same as Array or [].
So if you want to copy an object you'd have to iterate over every element of that object till you find an primitive type. This can be tedious and quite hard even (http://andrewdupont.net/2009/08/28/deep-extending-objects-in-javascript/) this is called a deep copy.
But in this case a shallow copy (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice) is enough
var objects1 = samount.slice(0);

Related

How to overwrite JavaScript object values using Object()

I am still somewhat new to JavaScript, Node, etc. and come from a Groovy background (which has extremely similar syntax to JavaScript). In Groovy, I can easily do something like this:
def myMap1 = {};
def myMap2 = {};
myMap1["key1"] = "value1";
myMap1["key2"] = "value2";
myMap1["key3"] = "value3";
myMap1.each() { key, value =>
myMap2[key] = value;
}
This would iterate through the existing map (myMap1) and copy the values for each key to the new map (myMap2), with the same key names. Easy as pie. However, JS has a concept of the prototype, which has been driving me crazy because you have to use hasOwnProperty, the index of the item sort of thing, etc and it results in a lot of code for something that's supposed to be really simple.
Looking at the MDN docs for Object(), it looks like JS has implemented something that allows a developer to access key/value pairs without having to deal with prototyping and all of that stuff, and you can just access the data in the object, and not properties of the object. I now have this:
var existingData = {"foo":"thing","bar":"otherThing","baz":"whatever"};
var update = {"foo":"newStuff","bar":"thisChanged","baz":"arghh"};
for (const [ key, value ] of Object.entries(update)) {
console.log("Old value is " + existingData[key]);
existingData[key] = value;
console.log("Setting " + existingData[key] + " to " + value);
}
I would think this would work, but I get this in the console instead:
Old value is undefined
Setting thing to thing
Old value is undefined
Setting otherThing to otherThing
Old value is undefined
Setting whatever to whatever
It looks like existingData[key] does not reference the key in the key/value pair, but instead the value or something? How do I tell it, "for this key name in this second object, set this value?" I've been searching forever on Google and everything is either doing it the old way (with indexes) or is overly complicated for no particular reason. Any help would be greatly appreciated.
for (let key in map1) {
map2[key] = map1[key];
}
BTW why you dont use Object.assign(); ? (notice: it returns a new object)
let update = { "key1": "value1", "key2": "value2" };
let map2 = Object.assign({}, map1, update);
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
Simply use Object.assign(map2, map1) to update map2 (copy key/value of map1 to map2)
Or you can use,
map2 = {...map2, ...map1} to build a new object and replace the map2 completely
To have a deep copy, instead of only first level you can use JSON.parse(JSON.stringify(map2)) instead of map2. If you think, its a large object and that impact performance, go for a nested implementation of copy recursively! ;-)
You could just do this - looping through an array of the keys:
let myMap1 = {};
let myMap2 = {};
myMap1["key1"] = "value1";
myMap1["key2"] = "value2";
myMap1["key3"] = "value3";
// create an array of the keys in the object myMap1
let myMap1_keys = Object.keys(myMap1);
// loop through the array of object keys
for (let i = 0; i < myMap1_keys.length; i++) {
myMap2[myMap1_keys[i]] = myMap1[myMap1_keys[i]];
}
I would advise not using a for..in loop i.e. as used in one of the other answers as these are slower than a native for loop (as used above). You can see some details regarding performance here: Comparing JavaScript loops performance (for, do while, for in)
If you are just interested in literally duplicating the object you can do that like so:
let myMap2 = JSON.parse(JSON.stringify(myMap1));
Anouther answer suggested using Object.assign() and anouther suggested using ES6 spread operators but these will 'shallow' copy the object which means the objects are using references to the original object and will only copy the top level of the object - the method above deep copies the object which I usually find is what is required for most use cases and will copy every level of the object.
You can iterate over keys. check is this helpful to you
var m1 = {};
let m2 = {};
m1["key1"] = "abc";
m1["key2"] = "def";
m1["key3"] = "ghi";
var m1_change_key = Object.keys(m1);
for (var i = 0; i < m1_change_key.length; i++) {
m2[m1_change_key[i]] = m1[m1_change_key[i]];
alert(m2[m1_change_key[i]])
}

Convert String to already declared object in JavaScript?

I have this code:
//Arguments are unique.
var Object1 = new Object(argument,argument,argument);
var Object2 = new Object(argument,argument,argument);
var Object3 = new Object(argument,argument,argument);
//...
var Object100 new Object(argument,argument,argument);
function convert(){
var array = ["Object1","Object56"];
// Manipulate values in array above as if they were the objects already
//declared above this function, like acessing "Object56.argument" property.
}
I need to convert the the strings in the array to the objects that have already been declared, in order to manipulate the objects properties (which are converted from the arguments) in a function. I realize I'm basically turning JS objects into a database which is probably a bad idea but I was wondering if there's a solution to this? They way the values in the array are chosen is fairly complex and I think it would detract from the question, but they are randomly generated more or less.
Instead of storing each object as a separate variable, create a map:
var objectMap = {
Object1: new Object(argument, argument, argument),
Object2: new Object(argument, argument, argument),
// ...
Object100: new Object(argument, argument, argument)
};
The mapping would then be easy enough.
You can either do it manually:
var array = ['Object1', 'Object2'];
var objects = [];
for(var i = 0; i < array.length; i++) {
var key = array[i];
objects.push(objectMap[key]);
}
Or (if you're supporting ES5) use the map function:
var array = ['Object1', 'Object2'];
var objects = array.map(function (key) {
return objectMap[key];
});

Copying a javascript array inside a class protoype function [duplicate]

This question already has an answer here:
Deep copying array of nested objects in javascript [duplicate]
(1 answer)
Closed 6 years ago.
I have this class on javascript:
function Node(board,x,y,t){
this.board = board;
this.x = x;
this.y = y;
this.playerTile = t;
this.oponentTile = getOponentTile(this.playerTile);
this.parent = null;
this.getChildren = getChildren;
};
and I´m using this function which copies the this.board variable (which is an array) to the tempBoard variable using slice()
var getChildren = function() {
if(this.x==-1 && this.y ==-1){
var moves = getAllValidMoves(this.board,this.playerTile);
}
else{
var tempBoard = this.board.slice();
makeMove(tempBoard,this.playerTile,this.x,this.y);
var moves = getAllValidMoves(tempBoard,this.playerTile);
}
var children = [];
for(var i = 0;i<moves.length;i++){
var currentMove = moves[i];
var currentBoard = this.board.slice();
if(this.x==-1 && this.y ==-1){
children.push(new Node(currentBoard,currentMove[0],currentMove[1],this.playerTile));
}
else{
makeMove(currentBoard,this.playerTile,this.x,this.y)
children.push(new Node(currentBoard,currentMove[0],currentMove[1],this.oponentTile));
}
}
return children;
};
the problem is that after calling makemove() both the tempBoard and the this.board variables are being modified.
Is there any way I can copy an array without it´s reference?
.slice() makes a shallow copy of the array, not a deep copy.
That means that if you have an array of objects and you use .slice() to make a copy of the array, it gives you a new array that is a first level copy. But the new array points to all the same objects as the first array. You can rearrange the copied array or remove elements from it and that will not affect the first array.
But, if you modify the objects in the array, it is the same objects in both arrays so making a modification to any object in the array (such as changing a property on the object) will be seen in both arrays.
If you want a full copy of the array and it's contents, then you have to make a deep copy which is a bit more complicated and can slightly depend upon what exactly you have in the array.
There are many different ways to make a deep copy. You can read about many of them in these references:
How do I correctly clone a JavaScript object?
Copying an array of objects into another array in javascript (Deep Copy)
Copying array by value in JavaScript
If you are guaranteed not to have any circular references in your array (where one object points to another which points back to it), then the simplest way to make a copy is this:
var tempBoard = JSON.parse(JSON.stringify(this.board));
maybe help
function copy(data){
var result = JSON.stringify(data);
return JSON.parse(result);
}

Javascript arrays remaining identical after one is changed

I am making an app in which an algorithm is run on an array. Because the contents of the array will change during the execution of the algorithm, I'm storing the array contents to another array beforehand - performing the 'if' statements on the source array but updating the temporary array, then equating them afterwards.
The problem is that after running the algorithm, the two arrays are still identical. It seems that updating the temporary array automatically updates the source array.
I've created this jsfiddle to demonstrate:
var a = new Array( 0 , 1 , 2 );
var b = a;
b[1]=3;
document.write( (a[1]==b[1]) );
//Should show 'false' as this will not be correct
The code above returns "True". Is this normal behaviour? How can I overcome this?
That is normal behaviour, when copying array you are actually making a reference, so when you do var b = a that means instead of copying value you are just copying the reference
if you want to shallow copy an array (array with only one depth level) then you can use simple method like this:
var b = a.slice(0);
But if you want to deep copy an array (array with 2 or more depth level) then you can use below method for that:
var objClone = function(srcObj) {
var destObj = (this instanceof Array) ? [] : {};
for (var i in srcObj)
{
if (srcObj[i] && typeof srcObj[i] == "object") {
destObj[i] = objClone(srcObj[i]);
} else {
destObj[i] = srcObj[i];
}
}
return destObj;
};
For use of both of these methods check this jsFiddle
b = a doesn't copy the array, but a reference. Use b = a.slice() to make a copy.
See also ...
As others have mentioned a = b does not copy the array. However, if you do end up using the .slice() method to copy arrays please note that objects within an array will be copied by reference.
Take the following example
var obj = { greeting: "hello world" };
var a = [ obj ];
var b = a;
a[0].greeting = "foo bar";
b[0].greeting // => "foo bar";
Other than that you are good to go :)

javascript push multidimensional array

I've got something like that:
var valueToPush = new Array();
valueToPush["productID"] = productID;
valueToPush["itemColorTitle"] = itemColorTitle;
valueToPush["itemColorPath"] = itemColorPath;
cookie_value_add.push(valueToPush);
the result is [];
what am i do wrong?
Arrays must have zero based integer indexes in JavaScript. So:
var valueToPush = new Array();
valueToPush[0] = productID;
valueToPush[1] = itemColorTitle;
valueToPush[2] = itemColorPath;
cookie_value_add.push(valueToPush);
Or maybe you want to use objects (which are associative arrays):
var valueToPush = { }; // or "var valueToPush = new Object();" which is the same
valueToPush["productID"] = productID;
valueToPush["itemColorTitle"] = itemColorTitle;
valueToPush["itemColorPath"] = itemColorPath;
cookie_value_add.push(valueToPush);
which is equivalent to:
var valueToPush = { };
valueToPush.productID = productID;
valueToPush.itemColorTitle = itemColorTitle;
valueToPush.itemColorPath = itemColorPath;
cookie_value_add.push(valueToPush);
It's a really fundamental and crucial difference between JavaScript arrays and JavaScript objects (which are associative arrays) that every JavaScript developer must understand.
Use []:
cookie_value_add.push([productID,itemColorTitle, itemColorPath]);
or
arrayToPush.push([value1, value2, ..., valueN]);
In JavaScript, the type of key/value store you are attempting to use is an object literal, rather than an array. You are mistakenly creating a composite array object, which happens to have other properties based on the key names you provided, but the array portion contains no elements.
Instead, declare valueToPush as an object and push that onto cookie_value_add:
// Create valueToPush as an object {} rather than an array []
var valueToPush = {};
// Add the properties to your object
// Note, you could also use the valueToPush["productID"] syntax you had
// above, but this is a more object-like syntax
valueToPush.productID = productID;
valueToPush.itemColorTitle = itemColorTitle;
valueToPush.itemColorPath = itemColorPath;
cookie_value_add.push(valueToPush);
// View the structure of cookie_value_add
console.dir(cookie_value_add);

Categories