Let arr = [1,2,3,4]. If I set arr[x] where x >= arr.length, arr.length becomes x + 1.
This happens on Firefox and Chrome. I have two questions:
Is this defined behavior? (source would be welcome)
Is doing this recommended?
Thanks!
Is this defined behavior?
Yes, see ยง15.4 of the spec.
Is doing this recommended?
It depends entirely on what end result you want. There's nothing wrong with doing it.
You'll quite commonly see arrays built up like this:
var a = [];
for (/*...some loop over things...*/) {
a[a.length] = /* ...something to put on the array... */;
}
...which is exactly the same as:
var a = [];
for (/*...some loop over things...*/) {
a.push(/* ...something to put on the array... */);
}
Some JavaScript engines process the a[a.length] = ... faster than the a.push(...) (others are the opposite).
Note that JavaScript arrays are sparse, they can have gaps in them, which is part of the reason for this behavior. (In fact, JavaScript arrays aren't really arrays at all.) You can assign assign to the length property.
Array indexes start from zero.
arr[0] == 1
arr[1] == 2
arr[2] == 3
arr[3] == 4
When you set arr[4], it becomes the 5th element.
Sure, you could do this in JavaScript.
The array will extend to the xth index, and place your value there.
The length of the array will be x+1.
The values in the indexes in between that were never defined, 4 to x-1 in your case, will be undefined.
Related
I know the classic way of looping through an array arr is:
for(var i=0 ; i<arr.length ; i++) {
// code
}
But someone recently showed me a different way of implementing the condition inside that loop, like this:
for(var i=0 ; arr[i] !== undefined ; i++) {
I think this solution is interesting because this is exactly what you need when you loop through an array: you don't want to get undefineds when you try to access an undefined index.
I realize that if you count the characters it looks longer, and also that you might have some problems with arrays like this: ["Hello", , "World"], but apart from that - is there anything else I'm missing here? Why shouldn't we be using this technique instead?
Why shouldn't we be using this technique instead?
It doesn't work on sparse arrays (as you mentioned)
It doesn't work on arrays that contain undefined values
It's not as easily optimised (assuming the .length stays constant during the loop)
(In the old days, the undefined identifier could be overwritten, you'd need to use typeof)
Of cource, wheter it "works" for you depends on the use case, and sometimes you might want to use it. Most times, you simply don't.
And even if both ways would work in your case, it's better practise to use the standard approach (i<arr.length) as there is lower mental overhead. Everyone recognises that pattern and knows what it does, while with arr[i]!==undefined one would need to think about why the uncommon approach was chosen.
Sometimes arrays have empty values and your way of iteration will fail.
var arr = [];
arr[5] = 5;
for (var i = 0; arr[i] !== undefined; ++i) {
console.log(arr[i]);
}
console.log('done');
If you want to iterate real array values and skip undefined's, i suggest you to filter the array first and do iteration after. So your code will be more understandable. Example:
var arr = [];
arr[5] = 5;
arr.filter(Boolean).forEach(function (e) {
console.log(e);
});
console.log('done');
"abc":[{"a":"a"},{"b":"b"},{"c":"c"}];
I got this from my ajax's data callback, how can I know there's 3 object in it? I tried .length method but it grave me the wrong number.
Using .length on the array will give you the correct answer 3, but most likely you're doing data.length which is wrong in your case.
data["abc"].length will yield correct result.
Use Below code you will get 3 in console :
<script>
var test = {"abc":[{"a":"a"},{"b":"b"},{"c":"c"}]};
console.log("Length :"+test.abc.length);
</script>
It doesnt matter if you have objects in your array or other elements, array.length always works on it.
Readup: Array.length - JavaScript | MDN
The code that you have posted, it looks like abc is a property of an object.
var obj = {
"abc":[{"a":"a"},{"b":"b"},{"c":"c"}] // semicolon removed
};
alert(obj.abc.length); // compute length/number of objects here
Array.length will give you the number of elements in the array.
Your example
([{"a":"a"},{"b":"b"},{"c":"c"}].length == 3) // => true
So your issue lies elsewhere.
Can anyone explain why the second alert says 0 ?
var pollData = new Array();
pollData['pollType'] = 2;
alert(pollData['pollType']); // This prints 2
alert(pollData.length); // This prints 0 ??
The length of the array is only changed when you add numeric indexes. For example,
pollData["randomString"] = 23;
has no effect on length, but
var pollData = [];
pollData["45"] = "Hello";
pollData.length; // 46
changes the length to 46. Note that it doesn't matter if the key was a number or a string, as long as it is a numeric integer.
Besides, you are not supposed to use arrays in this manner. Consider it more of a side effect, since arrays are objects too, and in JavaScript any object can hold arbitrary keys as strings.
Because you haven't put anything into the array yet. You've only been assigning to a dynamically-created pollType attribute on the array object.
If you use numeric indices, then the array automagically takes care of length. For example:
var arr = [ ]; // same as new Array()
arr[2] = 'Banana!';
alert(arr.length); // prints 3 (indexes 0 through 2 were created)
The length property takes into consideration only those members of the array which names are indexes (like '1', '2', '3', ... ).
Arrays in JavaScript have numeric indexes only.
Use an object, which is essentially what you are doing above, setting properties on that array object.
array.length returns how many values are stored in the array. The first alert is returning the value of the position 'pollType'.
The reference guide I always use when needing help with javascript arrays is this page http://www.hunlock.com/blogs/Mastering_Javascript_Arrays
I'd also read what it says under the heading Javascript Does Not Support Associative Arrays, as you may run into problems with this also.
var pollData = Array();
function test() {
pollData[0] = 2
alert(pollData[0]);
alert(pollData.length);
}
//[x] is the array position; hence ['polltype'] is causing issues
When I do something like this:
var o = new Array();
o[20] = true;
o[1000] = true;
o[4000] = true;
Is it reasonable to expect that only 3 elements will be allocated or can the implementation decide to suddenly allocate something with 4000 elements?
The reason I'm asking is that when I do this I see in firebug an indication that there are actually 4000 undefined in o. are they really there?
Now that we know that o is an Array, I can answer you precisely.
No, the elements will not be 'allocated' or 'created'.
When you make an assignment of an index property to an Array object, which is greater than the actual length of the array two things happen:
The index named property is created
The length property is incremented, to be the index + 1
For example:
var o = [];
o[4000] = true;
o.hasOwnProperty(0); // false, the property doesn't exist
o.hasOwnProperty(1); // false
o.hasOwnProperty(4000); // true, the property exist
As you can see, the hasOwnProperty method returns false when we test the presence of the 0 or 1 properties, because they don't exist physically on the object, whereas it returns true for 4000, the property that was created.
When Firebug detects that the object being printed in the console is an array-like object, it will simply make a loop, showing each of the index values from 0 to length - 1.
Firebug detects array-like objects simply by looking if they have a length property whose its value is an unsigned 32-bit integer (less than 2^32 - 1), and if they have a splice property that is a function, for example, the following object will be detected and printed as an Array on the Firebug's console:
console.log({length:3, splice:function(){}});
// Firebug will log: `[undefined, undefined, undefined]`
a) That code is not valid. You need either var o = {}; // object or var o = []; // array.
b) In the first case, the object is sparse. In the second, it may depend on the interpreter; in modern browsers it is also sparse. Try o[99999999] = "hi"; and see how much memory your browser does or does not allocate. If it does not go up by at least 10MB, your arrays are sparse.
I think this one answers the question.
Are Javascript arrays sparse?
And according to that one, arrays are spares, thats is, if you use for(item in array) you only get 3 items, not 4000 but if you use array.length it will take the larges integer value and return one larger, look here:
http://www.crockford.com/javascript/survey.html
Linkpad will use a for(item = 0; item < array.length; item++) and that one will return undefined for any index that is not present in the array.
/*
On the other hand, if you have a very large index any array manipulation will have to loop
through each index- it won't skip from one defined item to the the next defined item.
*/
var A= [];
A[0]= 'a';
A[10]= 'b';
A[4000000]= 'c';
alert(A.filter(function(itm){
return itm!= undefined;
}));
Javascript will generate all elements inbetween, always. You may want to use o.length to verify the length of the array. It will return 4000 and not 3.
In the following code why the variable 'a' refer to the index rather than the value ?
for (var a in Values) {
alert(Values[a]);
}
That's by design. It's trivial to get a value in an array when you know its key, but it's much harder to get a key given a value. Values can be duplicated, so how do you know which key should be used? But a key's unique, so given a key, there's only ever one value to retrieve. So, the for loop will iterate over the keys, and it's trivial to get the associated value.
Think of a JavaScript Array as a normal Object with a special property named length (actually, it a bit more complex). So the for..in loop behaviour is identical as for other objects:
var a = new Array();
a[1] = "a";
alert(a.length); // 2
alert(a[0]); // undefined
a[1000] = "b"
alert(a.length); // 1001
a[-1] = "c";
alert(a[-1]); // c
a.abc="why not";
for(var key in a)
{
alert(key+"="+a[key]);
}
// 1=a
// 1000=b
// -1=c
// abc=why not
Also note that you can have gaps within your array without having to pay the memory price.
There is a for each...in loop that does exactly that - enumerates only values. Coming soon to a browser near you.
for each(var a in Values) {
..
}
For arrays, there is a new function forEach which achieves the same.
someArray.forEach(function(value) {
..
});