I have found a behavior I did not expect when trying to use a loop in order to change the value set for a property in an object.
Basically, I declare my object outside the loop.
Then I loop on an array of numeric values, which values are used to update the object property.
Inside the loop, I store the current object state inside an external array.
The result is that instead of having an array containing a series of objects with different numeric values, I end up having the same numeric values in each object stored.
Here is the fiddle http://jsfiddle.net/fAypL/1/
jQuery(function(){
var object_container = [];
var numeric_values = [1, 2 , 3, 4];
var my_object = {};
jQuery.each(numeric_values, function(index, value){
my_object['value'] = value;
object_container.push(my_object);
});
jQuery.each(object_container, function(index, value){
jQuery('#content').prepend(value['value']);
});
});
I would expect to get 1 2 3 4 as values stored in each object, however, what I get is 4 4 4 4, which does not make sense to me.
Any hint on this behavior is more than welcome, thanks
When your code calls .push() and passes my_object, what's being passed is a reference to the object. No copy is made.
Thus, you've pushed four references to the exact same object into the array.
JavaScript objects always participate in expressions in the form of references. There's no other way to deal with objects. Thus when you create a variable, and set its value to be an object, you're really setting its value to be a reference to the object. Same with parameter passing, and anywhere else an object can appear in an expression.
In this case, you can create new objects pretty easily; just dispense with my_object and push a fresh one on each iteration:
object_container.push( { value: value } );
You are not creating a new object each time around the loop - you are just updating the same existing object and pushing references of that to the object array. To create a new object you want to do something like:
my_object = { 'value': value };
object_container.push(my_object);
In this case you now will get something more like what you were looking for. See the updated fiddle here: http://jsfiddle.net/fAypL/2/.
Best of luck!
One more thought (Clone!) - If you are really tied to using the same object each time, just clone the object before you add to the array. There is a great solution for that here.
You are using jQuery so if what you want is to merge without effecting the original look at :
var both_obj = $.extend( {}, default_obj , adding_obj );
This will leave your original object changed, also good to use for a copy.
jquery docs - extend()
An alternate version is to use an object with a constructor and the new keyword:
var object_container = [];
var numeric_values = [1, 2 , 3, 4];
function MyObject(value)
{
this.value = value;
}
jQuery.each(numeric_values, function(index, value){
object_container.push(new MyObject(value));
});
jQuery.each(object_container, function(index, value){
jQuery('#content').prepend(value['value']);
});
Fiddle
Related
I am in a strange condition. I have an array of objects, I used angular.forEach to modify each object price key value but when I am changing it in each it is also changing main array object as well.
Have a look on code, you will understand then what I am trying to say.
var option_1_val = $scope.options.option_1_val;
var option_2_val = $scope.options.option_2_val;
console.log('genies',sc.genies);
var new_arr = [];
var each ;
each = sc.genies;
angular.forEach(each,function(val,key){
var ob = {};
ob = val;
var priceA = angular.fromJson(ob.price);
console.log('price',priceA);
var option = option_1_val.replace(" ","-")+","+option_2_val.replace(" ","-");
console.log(option);
ob.price = priceA[option];
console.log(ob);
new_arr.push(ob);
});
option = 'Non-Vegetarian,' (after calculating)
sc.genies = [{"gs_id":"3","user_id":"25","service_id":"7","price":"{\"Vegetarian,Bengali\":\"200\",\"Vegetarian
,Chinese\":\"3100\",\"Vegetarian,Gujarati\":\"800\",\"Vegetarian,Italian\":\"100\",\"Vegetarian,Maharashtrian
\":\"100\",\"Vegetarian,Punjabi\":\"100\",\"Vegetarian,-South-Indian\":\"300\",\"Vegetarian,Thai\":\"100
\",\"Non-Vegetarian,Bengali\":\"1100\",\"Non-Vegetarian,Chinese\":\"3100\",\"Non-Vegetarian,Gujarati
\":\"100\",\"Non-Vegetarian,Italian\":\"100\",\"Non-Vegetarian,Maharashtrian\":\"100\",\"Non-Vegetarian
,Punjabi\":\"100\",\"Non-Vegetarian,-South-Indian\":\"80\",\"Non-Vegetarian,Thai\":\"100\",\"Jain,Bengali
\":\"2100\",\"Jain,Chinese\":\"2100\",\"Jain,Gujarati\":\"4100\",\"Jain,Italian\":\"100\",\"Jain,Maharashtrian
\":\"100\",\"Jain,Punjabi\":\"100\",\"Jain,-South-Indian\":\"800\",\"Jain,Thai\":\"100\"}","min_price"
:"80","max_price":"4100","username":"abdul quadir","email":"abdul.quadir#kiozen.com","rating":"3"}]
now when I am repeating sc.genie, I have taken it in a new variable already "each" and then I am changing "price" key of each array to undefined but strange point is when I see in console value of price in sc.genies is also changed to "undefined". Huh!
I hope you got my point, please help me why is that happening.
Thanks
You should use angular.copy then when change in each value not affect to original value. because of angular.copy assign old value in new variable without reference.
like:
var each ;
each = angular.copy(sc.genies);
instead of
each = sc.genies;
There is a simple answer. The reason why "both" values changes, is because it is actually the same object. The variable val from this line angular.forEach(each,function(val,key){ ... contains a pointer to an object. It is not another object. It is the same object, it is only accessed via different variable name.
If you really want the original and working copy to be different objects, then you need to manually create new instance with the same values.
You can create copy of an object like this (good for simple objects):
var copy = JSON.parse(JSON.stringify(originalObject));
or as pointed in the comment above, you can use angular.copy(source, destination). See the documentation https://docs.angularjs.org/api/ng/function/angular.copy
Newbie here...be nice.
I have an empty object that will get pushed into an array.
listView = {};
I add properties to it.
listView.code = code;
listView.description = description;
I push the results object into an array.
listy.push(listView);
Each time I enter a new selection in step #2 it overwrites the object instead of adding the new object properties to the array. It also increments the index by one, so it just repeats...
[{"code":"I77.812","description":"Thoracoabdominal Aortic Ectasia"}]
[{"code":"I77.811","description":"Abdominal Aortic Ectasia"},{"code":"I77.811","description":"Abdominal Aortic Ectasia"}]
[{"code":"I06.1","description":"Rheumatic aortic insufficiency"},{"code":"I06.1","description":"Rheumatic aortic insufficiency"},{"code":"I06.1","description":"Rheumatic aortic insufficiency"}]
The array should contain three different objects. But instead it has three copies of the newly added one...
How should I be adding the new choice objects so that they don't get overwritten?
You are always adding a reference to the same object, and changing that same object, instead of adding new objects. See this:
var a = [];
var o = {};
for (var i = 0; i < 5; i++) {
o.id = i;
a.push(o);
}
a
// => [{"id":4},{"id":4},{"id":4},{"id":4},{"id":4}]
But
var a = [];
for (var i = 0; i < 5; i++) {
var o = {};
o.id = i;
a.push(o);
}
a
// => [{"id":0},{"id":1},{"id":2},{"id":3},{"id":4}]
The difference is, the second code always makes a new object that is distinct from all other objects already in the array.
As a metaphor, imagine a theatre director in casting. He turns to an actor, says "You... you'll be Romeo.". Then he looks at the same actor, says "You... you'll be Mercutio. Here, Mercutio, take this sword. Romeo... who told you to get a sword?!?" completely failing to realise that, if Romeo and Mercutio are the same person, if one of them picks up a sword, the other does it too.
Seeing as you declared yourself a 'newbie' i figured i'd take a bit more time explaining. When you push an object to an array, you don't copy the object. You just tell the array where to find the object (a reference). If you push the same object 3 times, the array just has 3 indexes at which it finds the same object. There's several ways around this, the easiest being that you declare the variable inside the loop
for (var i=0;i<3;i++){
var listView = {};
listView.id = i;
listy.push(listView);
}
This way listView is a different reference each time. The other way is to create a new object when you push
listy.push({id:listView.id, description:listView.description});
which works because simple variables are 'copied' into the array and not referenced.
your assignment of the properties of an object are simply replacing the existing properties. wh en you push the object in the array by name, you are push a reference to the object and not a value. This is why all the elements in the array are the same. You need to create a new object every time you push. Something like this should work for you.
listy.push({code:code, description:description});
try this :
listy.push({
code:listView.code,
description : listView.description
})
In my code I have used pass by value.
In your code , you are using Objects which are passed by reference .
You are adding same reference again and again so at the end you will get an array having all the values of same object .
To understand more about pass by value and pass by reference you can reffer this link :
Pass Variables by Reference in Javascript
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, ...)
How to initialize a string array (size<100 items) in javascript whose indexes are scattered over entire integer range, with data items.
If I do like this:
array1 = ["string1","string2","string3","string4"];
then I get array of length 4 with indices ranging 0 to 3
But in my case i want to keep my own indices, so that the array could be used like a high performance int-string hash table.
I'm preferably looking out for a single statement initialization.
The items of the array should be accessible like this: array1[23454]
Update From Comments
I'm restricted to initialize the array as a single statement since a dynamically prepared array initialization string is appended from server side like this: var array = <string from server here>
To create an array with a set number of indexes you can use
// Creates an array with 12 indexes
var myArray = new Array(12);
This isn't needed in javascript due to the way its array's work. There isn't an upper-bound for arrays. If you try to reference an item index in the array that doesn't exist, undefined is returned but no error is thrown
To create an array with perscribed indexes you can use something like array['index'] = value though this would force you to use multiple statements. Javascript doesn't have an array initalizer to allow for you to specify indexes and values all in a single statement though you can create a function to do as such
function indexArray(param) {
var a = [], i;
for (i=0; i<param.length; i+=1) {
a[param[i].index] = param[i].value;
}
return a;
}
var myArray = indexArray([
{ index: 123456, value : "bananas" },
{ index: 12, value : "grapes" },
{ index: 564, value : "monkeys" }
]);
var array1 = []
array1[23454] = 2
Just doing this should be fine. There's no set array size for javascript in the way there is for java.
If you really want to do this all in a single statement, you can make an object instead like this:
var object1 = {
"23454":2,
"123":1,
"50":3
};
and then retrieve the numbers like this:
object1["23454"] //2
I don't really recommend this though. The array method is a cleaner way of doing it even if it takes multiple lines since it doesn't require string conversion. I don't know enough about how these are implemented in browsers to comment on the performance impact.
Update
Since the 1 line requirement is based on something being passed to the server, I would recommend passing a JSON object to the server in the form:
"{"23454":2,"123":1,"50":3}"
then this code will parse it to an object:
var object1 = JSON.parse(jsonstringfromserver);
and if you like you can always convert that to an array by enumerating over the properties with a for in loop:
var array1 = []
for ( num in object1){
array1[num] = object1[num];
That is probably unnecessary though since object1[123] will already return 1. You only need this if you plan on doing array specific operations.
You don't have to pre-define the size of an array before you assign to it. For example:
var _array = [];
_array[0] = "foo";
_array[1000] = "bar"; // _array.length => 1001
_array[1] //undefined
No need to initialise the appropriate number of array elements before you assign to them.
Update
It already has been pointed out that you can use an object rather than an array. However, if you want to take advantage of array methods then this is still possible. Let me give you an example:
var obj = {
0: 15,
1: 10,
2: 5,
length: 3
};
If the object contains a length property then it can be treated as an array-like object. Although you can't call array methods directly from these objects you can use array methods.
Array.prototype.join.call( obj ); // 15,10,5
In fact using the ECMAScript 5 map function you can easily convert the above object to an array.
var _array = Array.prototype.map.call( obj, function( x ) { return x; } );
The map function does not exist in all browsers but you can use the following function if it doesn't.
Array.map = Array.map || function(a, f, thisArg) {
return Array.prototype.map.call(a, f, thisArg);
}
You can do what you want with an Object in this way:
var o = {23454: 'aaaa', 23473: 'bbb'};
You will lose the array methods/fields, e.g. length, but you will gain what you said you are looking for, and you will be able to add/remove members easily.
in this example, it seems that we can use a variable (here "second") to fill the array myArray, as if second was a "reference" to myArray : is that really what happens here?
var myArray = [];
var second = myArray;
second.target = … //we fill the "second" variable
second.offsetX = …
second.offsetY = …
var target = myArray.target; //then we retrieve the result from myArray
if (target) {
Thanks
second was a "reference" to myArray : is that really what happens here?
Yes.
Objects—like arrays—in JavaScript are passed and assigned by reference.
From your example, myArray and second both point to the same object in memory.
Yes, this is exactly what happens here. When you (for example) push new elements to second, you can read them later from myArray.
BTW, I sense that you're doing something strange. Why do you set an offsetX on an array?
This is called a shallow copy. You have a reference (var second = ...) to the original array (var myArray = ...), they both are pointing to the same memory in the memory of the JavaScript virtual machine.
This way you can access the array either by second or myArray.
var myArray = [];
This is just an array declaration It is same as var myArray=new Array();
About Array Referencing:
var second = myArray;
We are pointing the variable second to myArray memory location. Here new Object second will be created point to content of myArray. So, if you read content of second. It will read the myArray. But, you edit/update the content of second, content of myArray will be copied into second and it will be modified. As Bakudan said, It is the shallow copy. See the example below,
var myArray=[10,20,30];
var second =myArray; //second will contain 23,45 and 100.
If we update the array second, second=[100,200,300]
Original contents will be cleaned and 100,200,300 will be written.
To append the content to array second without removing the original content, We need to use function push as below:
second.push(100);second.push(200),second.push(300);
Now, content of second will be 10,20,30,100,200,300.
Object Property:
second.target = "testString";
second.offsetX =87;
second.offsetY =56;
This is the creation of object properties. It is same as,
second={"target":"testString","offsetX":87,"offsetY":56};
If you want to access value 87, it can be accessed as second.offsetX or second[offsetX].
More Information about java script Array is available here.