jQuery.grep changes original array - javascript

jQuery.grep() documentation clearly states that the process does not change the grepped array.
https://api.jquery.com/jquery.grep/
The following code finds a matching value from what I hope is an original, persistent array - arrLibrary.
I then modify the resulting commentObj...but the changes I make to it flow back into arrLibrary. Which I guess is not contradicting the jQuery documentation of GREP: we do create a new array, a subset of the original, but it still refers to the original and so changes made to it flow back to the original?
What am I missing? How do I get a subset of an array and then update data in it without messing up the original?
var commentObj = []; // Will hold the updated object for inserting into page and saving to DB
// FIRST, find full object from arrLibrary
if (source !== "chrome_logged"){
commentObj = $.grep(arrLibrary, function(commie){ // just use arr
return commie.uniqueID === obj.comment_id;
});
commentObj = commentObj[0];
} else {
commentObj = obj; // Just use what was passed
}
Later in my code I update commentObj.fieldwhatever = "this sucks" and the matching key/value in arrLibrary updates to match.
Any help/direction appreciated.

This seems crazy to me...but I understand...even though grep doesn't alter the original array - it results in a subset if there is a match - the resulting subset of data is still referring to the original.
So if you update the resulting array the original changes, too.
So I've done a deep copy to break the connection to the original...
var commentObj1 = []; // temp array - subset of arrLibrary...will still be connected to arrLibrary - reference
// FIRST, find full object from arrLibrary
if (source !== "chrome_logged"){
commentObj1 = $.grep(arrLibrary, function(commie){ // just use arr
return commie.uniqueID === obj.comment_id;
});
commentObj1 = commentObj1[0];
} else {
commentObj1 = obj; // Just use what was passed
}
var commentObj = $.extend(true, {}, commentObj1); // deep copy - break reference to arrLibrary

Related

How to translate a string to object notation

I'm working with a JSON validator that checks a give JSON object against a schema and returns errors if it doesn't match. One of the things I need to do is add missing attributes, but these could potentially be quite deep in the structure. The validator error returns the location of a missing attribute as a string in this format:
'data.thing1.thing2.thingN'
I can strip out the "data." bit easily enough, but I don't know how to translate the rest to correct object notation, in any depth. This is what I've got so far:
var attributeLineage = newField.split(".");
obj[attributeLineage[0]][attributeLineage[1]] = "";
So obviously this only works when there are only two levels of depth. I need to loop through the values in attributeLineage and link them all together to correctly construct the missing attribute in the given object, at any depth. How can this be done?
I might be missing something totally obvious, or going about it the wrong way, but I'm not sure how to proceed.
Using reduce() method get the reference of the inner object and update the property using last element in split array.
var newField = 'data.thing1.thing2.thingN';
// split the string
var attributeLineage = newField.split("."),
// get last element and remove it from splitted array
prop = attributeLineage.pop();
var ob = {
data: {}
};
// get the object reference
var obj = attributeLineage.reduce(function(o, k) {
// return if nested object is defined
// else define and return it
return o[k] || (o[k] = {}) && o[k];
}, ob);
// update the inner object property
obj[prop] = "hi";
console.log(ob);

Copying an array of objects into another array in javascript (Deep Copy)

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, ...)

JavaScript variables linked together for no good reason

I am working on a project in which I have a problem of one array variable suddenly containing the same as another one. With the help of the lazy man's alert prompts, I have narrowed the problem down to this piece of code, where everything suddenly goes wrong:
// The array "data" is the result of a JSON request - this works fine..
// "data" is a two-dimensional array.
allShowsVars = data.slice();
allShowsVars.sort(function(a, b) {
var aL = a[1].toLowerCase(), bL = b[1].toLowerCase();
if(aL < bL) return -1;
else if(aL > bL) return 1;
else return 0;
});
// At this moment, the allShowsVars variable holds the right contents from the data array..
showsVars = allShowsVars.slice(); // Here, we make a copy of allShowsVars..
for(var iS = 0, sPos; typeof showsVars[iS] != 'undefined'; iS++) {
sPos = showsVars[iS][1].indexOf(" - Season ");
if(sPos != -1) {
showsVars[iS][1] = showsVars[iS][1].slice(0,sPos);
if(iS > 0) {
if(showsVars[(iS-1)][1] == showsVars[iS][1]) showsVars.splice(iS,1);
iS--;
}
}
}
// I changed showsVars in the above for loop, cutting out " - Season ......" in a lot of entries.
Now, allShowsVars also has the new, changed contents from showsVars. Why???
The variables are not linked together!
I am thinking I missed something obvious somewhere. I just need someone clever enough to see it :)
This is from the documentation of Array.prototype.slice() from MDN.
For object references (and not the actual object), slice copies object references into the new array. Both the original and new array refer to the same object. If a referenced object changes, the changes are visible to both the new and original arrays.
This is what happening in your case.
You can use this hack to deep copy an array:
var deepCopy = JSON.parse(JSON.stringify(sourceArray));
See here and here for deep copying of JavaScript arrays/objects.
slice() only performs a shallow copy. Primitive values are copied directly, but nested objects are internally treated as references so both arrays end up pointing to the same objects.

Copying an array to a variable whilst excluding items - Performance

I have this array right here -
var children = [Group, Path,Path, CompoundPath,Path];
I would like to copy the array into a variable, which I do like this
var selectionItems = children.slice();
Now I would like when copying the array into the variable, to keep in selectionItems only the items that are Path's.
I have tried the splice() method but I think it messes up the indices of the copied array which is something I would prefer not to happen. I also have no idea how to exclude anything else other than Path in the new copy of the array.
As always any help would be appreciated.
You can use .filter:
var selectionItems = children.filter(function (el) { return el instanceof Path; });

javascript array push value of object

I am trying to create an array of objects, however when I am pushing onto my array it is adding a reference to the object rather than copying the values.
var nestedOrgList = [];
var tempTopOrg = {};
var i = 0;
while (typeof divList[i] !== 'undefined') {
tempTopOrg.org = divList[i++]; // increment i after we assign this
tempTopOrg.suborgs = [];
while ($(divList[i]).has('.expand').length < 1 && i < divList.length) {
tempTopOrg.suborgs.push(divList[i++]);
}
nestedOrgList.push(tempTopOrg);
};
Is there a better way to do this? Or do I need to do a manual copy?
nestedOrgList[insertIndex].org = tempTopOrg.org;
// etc..
insertIndex++;
You can check the following answer
How do I correctly clone a JavaScript object?
The JSperf
http://jsperf.com/cloning-an-object/82
definitely JavaScript should have a way natively to copy references.
A common method if speed is not a critical goal is to encode/decode the object using JSON:
var json = JSON.stringify(tempTopOrg);
nestedOrgList.push( JSON.parse(json) );
javascript passes objects and arrays by reference, so you will have to make a copy before pushing,
myarray.push(JSON.parse(JSON.stringify(obj)));
is quick and dirty and probably has performance issues,
this question tries to tackle cloning of objects.
to make a deep copy use
var newcopy = temp.slice(0);
and to filter undefined and null values use
newcopy = newcopy.filter(function(e){ return e });

Categories