I want to create an array of objects and then build a JSON string. I have the following code. After trying many times, I found the solution. Can anybody explain the difference between create and the new operator? It looks to me create is making a copy of the object.
HmiUserList = [];
var oco = {};
//If I use the following line it gives wrong string
//oco = Object.create({});
for (var i = 0; i < 3; i++) {
//If I use the following gives right string
oco = new Object();
oco.UserName = i.toString();
oco.GroupName = (i + 2).toString();
var count = HmiUserList.push(oco);
console.log(JSON.stringify(HmiUserList));
}
//Wrong string if I use the create or if I don't use the new for oco
[{"UserName":"2","GroupName":"4"},{"UserName":"2","GroupName":"4"},{"UserName":"2","GroupName":"4"}]
//Target string [{"UserName":"0","GroupName":"2"},{"UserName":"1","GroupName":"3"},{"UserName":"2","GroupName":"4"}]
The difference in behaviour is here not related to using Object.create or new. It is caused by where you put the assignment to oco: in the loop or before the loop.
When you do it before the loop, there is only one object, which the loop keeps mutating, iteration after iteration, and it pushes that same object in the output array. Even though the array ends up with 3 object references, all three represent the same object.
When you do it inside the loop, you create a new object in each iteration, so that your property assignments affect that object, and not an object that was already pushed onto the array. Your array ends up with 3 different objects as intended.
Related
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
This question already has answers here:
How can I create a two dimensional array in JavaScript?
(56 answers)
Closed 8 years ago.
I have declared a two-dimensional array, like so:
a = [[]]
However, when I try to give a second dimension value using a first dimension index other than 0, it doesn't work:
a[1][0] = "foo" //returns error
Is there a better way around this than manually defining every index you need as an array, i.e.:
a[1] = [];
a[2] = [];
a[3] = [];
//et cetera
N-Dimensional arrays do not exist in javascript - you have to just make arrays containing arrays as elements.
You're getting an error because a = [[]]; declares an array with one element, which happens to also be an array. Therefore a[0] is the internal array, but a[1] does not exist because you never declared it. The easiest way to properly declare a "two dimensional array" would be to use a loop:
var outerArray = [];
var numInternalArrays = 5;
for (var i = 0; i < numInternalArrays; i++) {
outerArray[i] = [];
}
If you know how many elements the root array should have you could do something like this:
var arr =
(Math.pow(2,10)-1).toString(2) // Binary string of 1s. Its length being 10
.split('') // Create an array from this string
.map(function(){return [];}); // Map a new empty array to each index
console.log(arr); // [[],[],[],[],[],[],[],[],[],[]]
This accomplishes the same thing:
for(var arr = [], i=10; i--; arr[i]=[]);
No need to declare arr outside of the for-loop since javascript doesn't have block scope, it will be added to the scope in which it is executed.
a = [[]]
This is an Array, with the first item being an array. Which is why indexing into the first item still works (a[0][0]).
If you want to access the second item as an array, you need to create your array as
a = [[],[]]
See this question for examples of
How can I create a two dimensional array in JavaScript?
If I understand correctly, use a loop:
for (var i = y; i--; a[i] = []);
There are no multidimensional arrays in javascript.
What you are doing is an array of arrays, but the outermost array has only one element (i.e. element 0) whose value is another array. So a[1] (or more generally a[1][x]) is invalid since the outermost array has only one element.
So you can do a[0][x] = "foo" but not the other way around.
So you can either initialize the array with a for loop or do something like var a =[[][][][][]];
You can have the array of arrays start as in:
var a = []; // start with the column array
Then when you want to put something in location [i][j] we can call 'i' the row-index and 'j' the column-index.
if (!a[i]) { // check for row existing
a[i] = []; // .. and create it if not
}
a[i][j] = 'foo'; // put something in the array cell
Note that this only works because we are always putting something in the new row array right after we create it. It might not work if you put 0 or "" in there instead of 'foo'.
There are a lot of things in javascript that are 'false' including 'null' and 'undefined' and '0' and I just don't know if an empty array or an array with one element that is an empty string are considered false. So you would have to do some experimenting with how, exactly to detect a missing row array so you can add it in.
i want to remove array element, but giving error while using splice,
i m using following function
with myAra as global var,
but in console ,it is giving me an error, TypeError: myAra.splice is not a function
var myAra = Array();
function charCounts(e,textAreaId)
{
myAra = $("#"+textAreaId).val();
var countNewLines = stringOccurrences(myAra, "\n");
if(myAra.length>75)
{
for (var i = 75; i >myAra.length; i++)
{
myAra.splice(i, 1);
}
$("#"+textAreaId).val(myAra);
}
}
myAra is a String, not an Array, at the point when you call splice. It has the value of the element.
This is a nice example of why globals are EVIL, sure you declared the variable an array (badly): var myAra = Array() (I'll explain at the end what's bad about this), but later on:
myAra = $("#"+textAreaId).val();//returns a string, variable is now a string, not an array
You've reassigned a string to the array, so the variable now references a string constant, and cannot be used as an Array (not safely, in a X-browser way at least).
Array() is bad, why? Well, for starters, you're calling a constructor, but you're not using the new keyword. With arrays that's not a big problem (it'll return a new instance all the same), but when you start defining your own objects, and constructors, you'll find yourself up to your neck in globals. Also, suppose you wanted an array and initialize the first element to an int: var anArray = new Array(2);, you won't get an array that looks like this: anArray[0] === 2, you'll get anArray === [undefined,undefined]. Compare that to var anArray('2') --> ['2']. Given the fact that JS is loosely typed, and you'll often use variables when initializing an array, it's hard to tell weather or not you're passing a numeric string or a number to the constructor. The best way to initialize arrays is by using the literal notation: [2,3,4], as an added bonus, it requires less typing, too
Replace the following:
if(myAra.length>75)
{
for (var i = 75; i >myAra.length; i++)
{
myAra.splice(i, 1);
}
$("#"+textAreaId).val(myAra);
}
with the below code:
if(myAra.length>75)
{
var moreNum = myAra.length - 75;
myAra.splice(75, moreNum ); // remove all items after the 75th item
$("#"+textAreaId).val(myAra);
}
Note - splice change the actual array, that's why the loop was failing. Hope it helps.
You are assigning a string value directly to the myAra so it will convert it to string ..typeOf myAra. Use myAra[0]=$("#"+textAreaId).val();...since javascript is a loosely coupled language
In the first line you used var myAra = Array(), but the jQuery val() function returns a string.
EDIT: Also I think the prefered way of creating arrays in JS is the var myArray = [], and not using the var myArray = new Array() expression.
I see four five options to initialize an array to a specific length in JS, (the last one is a stretch, I know):
var a = []; a.length = 5;
var a = Array(5);
var a = []; a[4] = undefined;
var a = new Array(5);
function makeArrayToLength(length, default){
var a = [], i = 0;
for(; i < length; i++){
a[i] = default;
}
return a;
}
I definitely want to (and do) use the literal whenever possible, but I'm in a situation where the defining aspect of a particular array is its length, so I'm leaning towards Array(5). Is the first example equivalent to the second in terms of end result? I realize it's not equivalent in the execution.
The first two, and the third examples are equivalent, at the end they produce an Array object with only one own property, length, containing 5 as its value.
When you call the Array constructor using a single numeric argument (like Array(5);), the newly created object will contain that number as its length property, the index properties aren't created:
var a = Array(5);
a.hasOwnProperty('0'); // false
The second example produces just the same:
var a = [];
a.length = 5;
a.hasOwnProperty('0'); // false
About the third example, it isn't equivalent because it will create a property on the array object, even though its value is undefined:
var a = []; a[4] = undefined;
a.hasOwnProperty('4'); // true
The fourth example:
var a = new Array(5);
Is just exactly the same as the second one (var a = Array(5);), there's no difference between using the Array constructor with or without the new operator, in the second example you are calling the Array constructor as a function.
And finally, about your makeArrayToLength function, by now I think you know isn't equivalent at all, since all the "index properties" are initialized to a "default" value. (BTW don't use default as Identifier, it's a Keyword...)
The Array constructor is usually avoided because it can have different behaviors depending the argument used, for example:
Array("5"); // one element array, (["5"])
Array(5); // empty array, length = 5
// v.s.
["5"] // one element array
[5] // one element array
Also, the Array constructor could be overriden, while array literals will always work.
Yes, they all produce the same result.
2 and 4 are the same because, according to the ECMAScript spec:
15.4.1 The Array Constructor Called as a Function When Array is called as a
function rather than as a constructor,
it creates and initialises a new Array
object. Thus the function call
Array(...) is equivalent to the object
creation expression new Array(...)
with the same arguments.
1 and 2 are equivalent because [] constructs a new array and setting the length property is equivalent to constructing an Array with new Array(length) (in the spec).
Option 3 is also equivalent because:
...whenever a property is added whose name is an array index, the length property is changed, if necessary, to be one more than the numeric value of that array index
And option 5 is basically just option 3, but repeated multiple times up to the maximum index.
I read at many tutorials that the current best practices to create a new javascript array is to use
var arr = []
instead of
var arr = new Array()
What's the reasoning behind that?
It might be because the Array object can be overwritten in JavaScript but the array literal notation cannot. See this answer for an example
Also note that doing:
var x = [5];
Is different than doing:
var x = new Array(5);
The former creates an initializes an array with one element with value of 5. The later creates an initializes an array with 5 undefined elements.
It's less typing, which in my book always wins :-)
Once I fixed a weird bug on one of our pages. The page wanted to create a list of numeric database keys as a Javascript array. The keys were always large integers (a high bit was always set as an indicator). The original code looked like:
var ids = new Array(${the.list});
Well, guess what happened when the list had only one value in it?
var ids = new Array(200010123);
which means, "create an array and initialize it so that there are 200 million empty entries".
Usually an array literal(var a=[1,2,3] or a=[]) is the way to go.
But once in a while you need an array where the length itself is the defining feature of the array.
var A=Array(n) would (using a literal) need two expressions-
var A=[]; A.length=n;
In any event, you do not need the 'new' operator with the Array constructor,
not in the way that you DO need 'new' with a new Date object, say.
To create Array without Length
var arr = [];
To create Array with Length more dynamically
var arr;
( arr = [] ).length = 10; // 10 is array length
To create Array with Length less dynamically
var arr = [];
arr.length = 10;