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

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);
}

Related

Newbie having some array problems [duplicate]

This question already has answers here:
Why does changing an Array in JavaScript affect copies of the array?
(12 answers)
Closed 8 months ago.
I am doing my first code project and I am having some problems with arrays changing their values apparently on their own
console.log(permanentDeck) should return 7 cards, but they seem to have been taken off
I've checked more than once for any line that changes permanentDeck value, but didnt find none
Can someone help me figure out in which line this happens??
var playerClass = "Warrior"
const examcard1 = {id:1, cost: 1, name:"Slash", text:"Deal 100% damage"}
const examcard2 = {id:2, cost: 1, name:"Block", text:"Gain 1 block"}
const examcard3 = {id:3, cost: 2, name:"Heavy Strike", text:"Deal 200% damage\nApply 1 vunerable"}
const starterWarriorDeck = [examcard1, examcard1, examcard1, examcard2, examcard2, examcard2, examcard3]
var deck
var permanentDeck = []
switch(playerClass){
case "Warrior":
permanentDeck = starterWarriorDeck
}
var drawPile = []
var hand = []
function shuffle(array){
let currentIndex = array.length, randomIndex;
// While there remain elements to shuffle.
while (currentIndex != 0) {
// Pick a remaining element.
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex--;
// And swap it with the current element.
[array[currentIndex], array[randomIndex]] = [
array[randomIndex], array[currentIndex]];
}
return array;
}
function restockDrawPile(){
drawPile = shuffle(deck);
}
function startBattle(){
deck = permanentDeck;
restockDrawPile();
}
function startPlayerTurn(){
drawCards(5)
}
function drawCards(cardsToDraw){
for(i = 0; i < cardsToDraw; i++){
let nextCard = drawPile.pop();
hand.push(nextCard);
}
}
var handView = new PIXI.Container()
startBattle();
startPlayerTurn();
console.log(permanentDeck);
console.log(deck);
console.log(drawPile);
console.log(hand);
´´´
if you add console.log(starterWarriorDeck);, you'll find that it has been modified as well. This is because arrays are passed by reference, so in the following lines, you're not making a copy of the array, just another reference to the same array:
permanentdeck = starterWarriorDeck;
deck = permanentdeck;
console.log(Object.is(deck, starterWarriorDeck)) // true
You need to explicitly copy the contents into the new array. There are multiple methods of doing a shallow copy in JS, but the clearest ones in this case would be to use the spread operator ... , or the .from method.
Examples:
permanentDeck = [...starterWarriorDeck]
deck = Array.from(permanentDeck)
Relevant info:
https://www.freecodecamp.org/news/how-to-clone-an-array-in-javascript-1d3183468f6a/
When you assign an array (e.g. permanentDeck) to a variable (e.g. deck) with deck = permamentDeck you just assign a reference the same underlying datastructure to deck. This means that deck and permanentDeck will both point to the same entity and if you modify any of the two you modify the same thing that both variables are referencing.
You'd need to make sure to make a true copy of the array to be able to modify deck without modifying permanentDeck
One of the simple methods to achieve such a "shallow copy" is to use the slice function of a javascript array.
// make a shallow copy of the array
deck = permanentDeck.slice();
Have a look at various methods to copy arrays.
https://www.freecodecamp.org/news/how-to-clone-an-array-in-javascript-1d3183468f6a/
Also make sure you understand and you're aware of the difference between a shallow copy and deep copy of arrays consisting of object references.

Using an object clone method and a for loop to push objects into array, the objects are all still the same reference and are the same in the array [duplicate]

This question already has answers here:
What is the most efficient way to deep clone an object in JavaScript?
(67 answers)
Closed 2 years ago.
let promiseArr = [];
for (let i = 0; i < ISOarr.length; i++) {
options.body.start_time = ISOarr[i];
let newOptions = cloneOptions(options);
promiseArr.push(newOptions);
}
console.log(promiseArr);
Returns an array of the same object.
Clone method:
cloneOptions = options => {
let clone = {};
for( let key in options ) {
clone[key] = options[key]
}
return clone;
}
So my question is how do I push an object that is not the same reference as the previous objects pushed, because even with it supposedly creating a new clone each loop it still somehow creates the same referenced object.
In the loop if I console.log I get the proper output with the value of the key changed, but once it's pushed into the array and we console.log the array, all objects are the same. Any suggestions would be super helpful. Thank you in advance!
Can you try this
cloneOptions = options => {
return JSON.parse(JSON.stringify(options))
}

Loop is adding too many items to the final array [duplicate]

This question already has answers here:
Array.fill(Array) creates copies by references not by value [duplicate]
(3 answers)
Closed 4 years ago.
When i use Array.fill to fill a multidimensional array, i get a weird behaviour when pushing to one of the arrays:
var arr = Array(2).fill([]);
arr[0].push(5);
console.log(arr);
//=> prints [[5], [5]]
fill is essentially doing this:
var content = [];
for (var i = 0; i < 2; i += 1) {
arr[i] = content;
}
So, your array will have a reference to the array you've passed to fill in each property.
It sounds weird, but what your code actually does is create an array ([]) and put a reference for that array in each of the items of the Array(2). So whenever you change that reference - every array that is referenced to that Array is changed.
It's exactly the same as:
var a = [];
var arr = Array(2).fill(a);
a.push(5);
console.log(arr[0][0], arr[1][0]);
a[0] = 2;
console.log(arr[0][0], arr[1][0]);
You can see that the values inside the arr are affected by the change to the a array.

How to clone an array in javascript without using JSON.stringify or JSON.parse? [duplicate]

This question already has answers here:
Copy array by value
(39 answers)
Closed 8 years ago.
I have an array example fruit . I'd like to copy it as array fruits2, without keeping reference.
As in the following example reference is kept so fruits is modified.
var fruit = function (name){
this.name = name;
}
var fruits = [];
fruits.push(new fruit('apple'));
fruits.push(new fruit('banana'));
fruits.push(new fruit('orange'));
var fruits2 = fruits;
fruits2.length = 0;
console.log(fruits);
http://jsfiddle.net/vkdqur82/
Using JSON.stringify and JSON.parse does the trick but the objects in fruits2 are not any longer of type fruit but are of general type object
var temp = JSON.stringify(fruits);
var fruits2 = JSON.parse(temp);
I would like to know an alternative approach which would keep inner object of fruit.
Use slice: var fruits2 = fruits.slice(); should do it.
Your jsFiddle, modified
See also: MDN
**Edit. I was a bit lazy, let's correct my answer to make up for that.
For an Array of just values slice is perfect. For an Array of objects or arrays or a mix of values/objects/arrays, the Array and Object elements of the Array to clone need cloning too. Otherwise they will be references to the original arrays or objects (so: not copies) and a change of one [of these references of arrays or objects] will be reflected in all 'clones' containing a reference to it.
To clone an Array of Arrays/Objects/mixed values Array.map is your friend. There are several methods to think of:
creating a new instance with old data
var fruits1 = fruits.map(function(v) {return new Fruit(v.name);});
using JSON
var fruits2 = fruits.map(function(v) {return JSON.parse(JSON.stringify(v));});
create and use some cloning method
var fruits3 = fruits.map(function(v) {return cloneObj(v);});
In case 3, a method for cloning could look like:
function cloneObj(obj) {
function clone(o, curr) {
for (var l in o){
if (o[l] instanceof Object) {
curr[l] = cloneObj(o[l]);
} else {
curr[l] = o[l];
}
}
return curr;
}
return obj instanceof Array
? obj.slice().map( function (v) { return cloneObj(v); } )
: obj instanceof Object
? clone(obj, {})
: obj;
}
Using this cloneObj method, Array.map is obsolete.
You can also use var fruitsx = cloneObj(fruits);
The jsFiddle from the link above is modified to demonstrate these methods.
For Array.map, see again MDN
slice can do the trick.
You can also use .map but .slice is normally faster.
var copy = fruits.map(function(item) {return item});
Hope it helps
You can declare a new array and use concat method, so that you concat all values from your array to the new array. Something like this:
var x = ["a","b"];
var a = [];
a = a.concat(x);
console.log(a);
I edited my poor answer.
Best regards.

Strange behavior in jQuery loop with arrays

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);

Categories