Javascript (beginner): Performance issue using arbitrary numerical properties? - javascript

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.

Related

Array length Vs Number of values in Array

Recently i had to make an Array with values at large indexes (due to plugin constraints).
eg:
var names[100000] = "a";
var names[150000] = "b" ... and so on till 5 large indexes.
and in between all values are undefined names[100001] //undefined.
Now my doubt is Since the array has only 5 elements but if i do
names.length //it is 300001
its a large Array. I am not iterating this array nor i am running any loop through it. I will get the values directly through their defined indexes from the array.
So will this structure make any significant performance differences on the Browser or is it alright to use this as long as the number of values in the array is less irrespective of its indexes and no iteration is involved.
Thanks
The only thing that differentiates an array from a plain object is its length property and how it behaves (and a few array specific methods of course). The length value simply increases with certain operations, like setting a numeric property or pushing a new element. That's it in a nutshell. The array doesn't actually contain 100000 elements when you set the property 100000 to a value, all that's happening is that you're setting one property and the value of length is adjusted accordingly.
So, no, it won't have a lot of impact on performance, unless somebody actually iterates through the array using for (let i = 0; i < arr.length; i++).
You can create an array with the length, given by your plugin and work locally with an object to limit the iterations. After all your processing has been applied, you copy the values to the array and send it to the plugin's function.
Keep an array with the desired length as a buffer
var buffer = new Array(20000);
Internally work with an object
var data = {};
Assign values to the object
data[10001] = "foo";
Once transformations or data processing has been applied to the object, copy data to the buffer
for (key in data){
buffer[key] = data[key];
}
Send buffer to the plugin. And clear data, if desired.
By doing so, you will not iterate more, than the actual data you processed.

How does JavaScript [] really work?

I'm writing a JavaScript interpreter for extremely resource-constrained embedded devices (http://www.espruino.com), and every time I think I have implemented some bit of JavaScript correctly I realise I am wrong.
My question now is about []. How would you implement one of the most basic bits of JavaScript correctly?
I've looked through the JavaScript spec and maybe I haven't found the right bit, but I can't find a useful answer.
I had previously assumed that you effectively had two 'maps' - one for integers, and one for strings. And the array length was the value of the highest integer plus one. However this seems wrong, according to jsconsole on chrome:
var a = [];
a[5] = 42;
a["5"]; // 42
a.length; // 6
but also:
var a = [];
a["5"] = 42;
a[5]; // 42
a.length; // 6
So... great - everything is converted into a string, and the highest valued string that represents an integer is used (plus one) to get the length? Wrong.
var a = [];
a["05"] = 42;
a.length; // 0
"05" is a valid integer - even in Octal. So why does it not affect the length?
Do you have to convert the string to an integer, and then check that when converted back to a string, it matches?
Does anyone have a reference to the exact algorithm used to store and get items in an array or object? It seems like it should be very simple, but it looks like it actually isn't!
As the specs said, and was noted by others:
"A property name P (in the form of a String value) is an array index if and only if ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal to 2^32-1."
That's explain why in your scenario "5" is considered an array index and "05" is not:
console.log("5" === String("5" >>> 0));
// true, "5" is equal to "5", so it's an index
console.log("05" === String("05" >>> 0));
// false, "05" is not equal to "5", so it's not an index
Note: the Zero-fill right shift is the shortest way in JS to have a substitute of ToUint32, shifting a number by zero.
See MDN
It's possible to quote the JavaScript array indexes as well (e.g.,
years["2"] instead of years[2]), although it's not necessary. The 2 in
years[2] eventually gets coerced into a string by the JavaScript
engine, anyway, through an implicit toString conversion. It is for
this reason that "2" and "02" would refer to two different slots on
the years object and the following example logs true:
console.log(years["2"] != years["02"]);
So with a["5"] you are accessing the array while a["05"] sets a property on the array object.
Arrays are just objects. That means they can have additional properties which are not considered elements of the array.
If the square bracket argument is an integer, it uses it to perform an assignment to the array. Otherwise, it treats it as a string and stores it as a property on the array object.
Edit based on delnan's comment and DCoder's comment, this is how JavaScript determines if it is an appropriate index for an array (versus just a property):
http://www.ecma-international.org/ecma-262/5.1/#sec-15.4
Arrays are also objects.
By doing this
a["05"] = 5;
You are doing the same thing as:
a.05 = 5;
However, the above will result in a syntax error, as a property specified after a dot cannot start with a number.
So if you do this:
a = [];
a["05"] = 5;
you still have an empty array, but the property of a named 05 has the value 5.
The number x is an array index if and only if ToString(ToUint32(x)) is equal to x (so in case of "05" that requirement is not met).

Javascript Array Length Behavior

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.

JavaScript array's length method

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

Question about the for loop in javascript?

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) {
..
});

Categories

Resources