I have a observable which is binded to UI, On button click i am creating a new array from observable array and doing manipulation with new array but unfortunately any changes in new array affects old array too.
I am using below code for deep copying.
var clonedArr = $.extend(true, [], masterArray());
Am i missing something. You can find jsfiddle here (https://jsfiddle.net/t5a1xfud/) for more details
You need to merge the empty array and your original array in a way that $.extend does not modify your original.
Example : https://jsfiddle.net/kyr6w2x3/18/
var newArr = [];
newArr = $.extend( [], self.Array(), newArr );
How to deep copy (or otherwise make sure the arrays aren't linked):
https://jsfiddle.net/t5a1xfud/18/
self.newItems(ko.toJS(self.existingItems()));
How to not deep copy (there are other ways too):
https://jsfiddle.net/t5a1xfud/19/
self.newItems(self.existingItems());
Note that in the second example after you use the "Copy to new" button, the arrays will be linked. They appear not to be linked, but if you alternate clicking between "Add to existing" and "Add to new" you will see that they do affect eachother. Not the case with the first example.
Related
I have two associative arrays and want to push one completely to the other.
my current code:
LT_WORK_PACKAGE.data[i].STOCK_DOCCAT = stock_data.STOCK_DOCCAT;
LT_WORK_PACKAGE.data[i].STOCK_DOCNO = stock_data.STOCK_DOCNO;
LT_WORK_PACKAGE.data[i].STOCK_ITMNO = stock_data.STOCK_ITMNO;
im looking for something like this:
LT_WORK_PACKAGE.data[i].push(stock_data);
.push is for adding items to an array. You do have an object , and to copy multiple properties into an object,you can use Object.assign:
Object.assign(
/*to:*/ LT_WORK_PACKAGE.data[i],
/*from:*/ stock_data
);
You can use LT_WORK_PACKAGE.data[i] = stock_data.
Note that the previous content (if it exists) of LT_WORK_PACKAGE.data[i] will be replaced by a reference to stock_data. Any changes made in stock_data will be done in LT_WORK_PACKAGE.data[i] If you want a copy, you can use : LT_WORK_PACKAGE.data[i] = JSON.parse(JSON.serialize(stock_data))
I want to clone my array of objects. Every one tells to use slice(0) but i don't understand, it's not working, check the fiddle. The property is avalaible in the two arrays.
I want to edit my objects in the first array and not in my second too.
I already checked : How to clone a Javascript Array of Objects? It's the same with concat, extend. The only one i found is JSON.parse. I want to understand why people say the method slice cloned arrays.
var arr = [{'obj1':1}, {'obj2':2}];
var clone = arr.slice(0);
clone[0].test = "defined";
https://jsfiddle.net/zkzv2mp0/2/
The fiddler is pure JS. does not havejquery included.
See working example:
https://jsfiddle.net/zkzv2mp0/3/
But as you can see using slice(0); is a Shallow clone, where you want to update one without updating the original (deep clone) JSON.parse(JSON.stringify(arr))
var clone = JSON.parse(JSON.stringify(arr));
You could use JSON Stringify and JSON Parse to clone an Array. But be careful this only works if your array contains JSON serializable content.
Ain't cristal clear what you want to do...
But here is what I think you try to achieve:
// Your initial array of objects.
var arr = [{'obj1':1}, {'obj2':2}];
// A cloned array of objects.
var clone = jQuery.extend(true, [], arr);
// Now sliced, keep the first object only
clone = clone.slice(0,1);
console.log(clone);
// Change the value of the object.
clone[0].obj1 = "defined";
console.log(clone);
// Show them in page.
$("#testarr").html(arr[0].obj1);
$("#testclone").html(clone[0].obj1);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>
In arr :
<span id="testarr">
</span></p>
<p>
In clone :
<span id="testclone">
</span>
</p>
I'm running a psychology experiment in js. I have an array of strings and I'm replacing the text in two of these strings.The array changes depending on the input I want from my participants. So I have the original array Array1, which contains some placeholder values, and a duplicate array that contains the values I want participants to see Array2. I enter the new values using .replace. Weirdly (or maybe it's just my understanding of js), using Array2[n].replace('placeholder', 'new text') replaces the placeholder in both arrays. Here's some script that replicates the issue (in Chrome).
Array1 = ['rhubarb', 'placeholder', 'rhubarb', 'rhubarb']
Array2 = Array1
Array2[1] = Array2[1].replace('placeholder', 'new text')
Array1
["rhubarb", "new text", "rhubarb", "rhubarb"]
Using Array2 = Array1.slice() eliminates the issue, so I guess Array2 = Array1 is only pointing to Array1 rather than copying it. Why does Array2 = Array1 allow modifications to Array2 to travel up the chain of reference, so to speak?
I'm sure this is fairly basic, but I'm not a programmer. Thanks in advance!
Your problem is actually, that two arrays are pointing to the same data; I mean they do not contain separate values. In order to copy values of an old array, you have better use .slice method. It looks like this
Array2 = Array1.slice()
Array2[1] = Array2[1].replace('placeholder', 'new text');
An array in javascript is also an object. Objects are treated as references. Basically they point to the same piece of data. The logical consequence is that if you modify one, it affects the other.
If you want to create a clone (independent copy) to avoid this kind of behavior you might want to refer to this question on how to duplicate arrays. It has plenty of answers.
Copying an array of objects into another array in javascript using slice(0) and concat() doesnt work.
I have tried the following to test if i get the expected behaviour of deep copy using this. But the original array is also getting modified after i make changes in the copied array.
var tags = [];
for(var i=0; i<3; i++) {
tags.push({
sortOrder: i,
type: 'miss'
})
}
for(var tag in tags) {
if(tags[tag].sortOrder == 1) {
tags[tag].type = 'done'
}
}
console.dir(tags)
var copy = tags.slice(0)
console.dir(copy)
copy[0].type = 'test'
console.dir(tags)
var another = tags.concat()
another[0].type = 'miss'
console.dir(tags)
How can i do a deep copy of a array into another, so that the original array is not modified if i make a change in copy array.
Try
var copy = JSON.parse(JSON.stringify(tags));
Try the following
// Deep copy
var newArray = jQuery.extend(true, [], oldArray);
For more details check this question out What is the most efficient way to deep clone an object in JavaScript?
As mentioned Here .slice(0) will be effective in cloning the array with primitive type elements. However in your example tags array contains anonymous objects. Hence any changes to these objects in cloned array are reflected in tags array.
#dangh's reply above derefences these element objects and create new ones.
Here is another thread addressing similar situation
A nice way to clone an array of objects with ES6 is to use spread syntax:
const clonedArray = [...oldArray];
MDN
Easiest and the optimistic way of doing this in one single line is using Underscore/Lodash
let a = _.map(b, _.clone)
You just need to use the '...' notation.
// THE FOLLOWING LINE COPIES all elements of 'tags' INTO 'copy'
var copy = [...tags]
When you have an array say x, [...x] creates a new array with all the values of x. Be careful because this notation works slightly differently on objects. It splits the objects into all of its key, value pairs. So if you want to pass all the key value pairs of an object into a function you just need to pass function({...obj})
Same issue happen to me. I have data from service and save to another variable. When ever I update my array the copied array also updated. old code is like below
//$scope.MyData get from service
$scope.MyDataOriginal = $scope.MyData;
So when ever I change $scope.MyData also change $scope.MyDataOriginal.
I found a solution that angular.copy right code as below
$scope.MyDataOriginal = angular.copy($scope.MyData);
I know that this is a bit older post but I had the good fortune to have found a decent way to deep copy arrays, even those containing arrays, and objects, and even objects containing arrays are copied... I only can see one issue with this code is if you don't have enough memory I can see this choking on very large arrays of arrays and objects... But for the most part it should work. The reason that I am posting this here is that it accomplishes the OP request to copy array of objects by value and not by reference... so now with the code (the checks are from SO, the main copy function I wrote myself, not that some one else probably hasn't written before, I am just not aware of them)::
var isArray = function(a){return (!!a) && (a.constructor===Array);}
var isObject = function(a){return (!!a) && (a.constructor===Object);}
Array.prototype.copy = function(){
var newvals=[],
self=this;
for(var i = 0;i < self.length;i++){
var e=self[i];
if(isObject(e)){
var tmp={},
oKeys=Object.keys(e);
for(var x = 0;x < oKeys.length;x++){
var oks=oKeys[x];
if(isArray(e[oks])){
tmp[oks]=e[oks].copy();
} else {
tmp[oks]=e[oks];
}
}
newvals.push(tmp);
} else {
if(isArray(e)){
newvals.push(e.copy());
} else {
newvals.push(e);
}
}
}
return newvals;
}
This function (Array.prototype.copy) uses recursion to recall it self when an object or array is called returning the values as needed. The process is decently speedy, and does exactly what you would want it to do, it does a deep copy of an array, by value... Tested in chrome, and IE11 and it works in these two browsers.
The way to deeply copy an array in JavaScript with JSON.parse:
let orginalArray=
[
{firstName:"Choton", lastName:"Mohammad", age:26},
{firstName:"Mohammad", lastName:"Ishaque", age:26}
];
let copyArray = JSON.parse(JSON.stringify(orginalArray));
copyArray[0].age=27;
console.log("copyArray",copyArray);
console.log("orginalArray",orginalArray);
For this i use the new ECMAScript 6 Object.assign method :
let oldObject = [1,3,5,"test"];
let newObject = Object.assign({}, oldObject)
the first argument of this method is the array to be updated,
we pass an empty object because we want to have a completely new object,
also you can add other objects to be copied too :
let newObject = Object.assign({}, oldObject, o2, o3, ...)
Here's some code that has two arrays(np and op), one a copy of the other
However, when I modify the copy, the original is also modified!
take a look:
<script type="text/javascript">
var op=new Array(0, 0);
var np=op;
np[1]=2;
document.write(op+"<br>")
document.write(np)
</script>
Is there any way to retain the original and modify the copy?
Some of the built in Array functions will actually create a copy for you. One such is slice.
For example:
var op=new Array(0, 0);
var np= op.slice(0);
np[1]=2;
document.write(op+"<br>")
document.write(np)
Reference http://my.opera.com/GreyWyvern/blog/show.dml/1725165
You never made a copy of the array. You simply assigned the array to another variable. This does not copy in Javascript. In your example there is only one array with two variables by which you can access it. There is no built-in way to copy arrays in Javascript so you will need to write your own function to do it.
Take a look at this StackOverflow question for a hint on how to actually implement the copying of the elements in the array.
What you are doing is not creating a copy of the array, it's only creating a copy of the reference to the array, so you get two references to the same array object.
This is how you can create an actual copy of the array:
var np = op.concat();
The concat method creates a new array that is a copy of the array with any additional items added. If you don't specify any additional items you just get a copy of the array.
Array.prototype.copy = function() {
return this.slice(0, this.length);
}
Then
var op=new Array(0, 0);
var np=op.copy();
np[1]=2;
document.write(op+"<br>")
document.write(np)
You should clone the second array instead of copying it.
--- Update
If you assign an object to a variable, only the reference is copied (that means, they both point to the same data). For having an independent copy of this object you need to clone it. And there are several ways how to this, for example here is the way of cloning object using jQuery.
You can just use the native slice method which returns a copy of the array:
var np = op.slice(0,op.length);
The second parameter should be optional, but in IE I believe it is required.
Your code, complete with the change:
var op=new Array(0, 0);
var np=op.slice(0,op.length);
np[1]=2;
document.write(op+"<br>")
document.write(np)
To create a new array you might want to consider:
var op = [];
To copy an array:
var np=op.slice();
or
var np=op.concat();
concat is faster, while slice takes up one less character. Some people alias "slice" or "concat" as "copy" so that it's more obvious that you're making a copy.
No need for parameters in either case. Parameters in the slice will just make the code larger and slower.