Loop through JavaScript object - which one is faster? - javascript

between saving a key name like this
for(var key in this.data)
{
var key_name = key;
for(key in this.data[key_name].content){
alert(this.data[key_name].content[key].score);
}
}
or making checkpoint objects for every parent node
for(var key in this.data)
{
var obj = this.data[key];
for(key in obj.content){
var inner_obj = obj.content;
alert(inner_obj[key].score);
}
}
which one has better performance? any other suggestion?

Only one way to know for sure: measure it.
http://jsperf.com/so-question-9853395
(click through for up-to-date results)

You should use a combination of the two:
for(var key in this.data)
{
var inner_obj = this.data[key].content;
for(ikey in inner_obj){
alert(inner_obj[ikey].score);
}
}
This would be the fastest way to do it compared to your two proposed solutions.
Please note that I renamed key to ikey inside the inner loop to avoid confusion.
After verification, my solution is indeed the fastest:
(source: minus.com)

Theoretically at least, the fastest would be to get the object reference outside the inner loop. In practice the difference might not be that big, if the browser is already doing this internally. Also, the performance might differ between browsers.
for(var key in this.data) {
var obj = this.data[key].content;
for(var key2 in obj){
alert(obj[key2].score);
}
}
Note that you should use separate variables for the loops, otherwise it will be hard to follow which values is in the variable at which point when you put some actual code in the loops.
Edit:
When I measure the performance in IE and Firefox, I find that this method is slightly faster than the methods proposed in the question. However, the difference is so small that you should not be concerned with it. Either method works just fine, and any performance concerns would be what you actually do with the values inside the inner loop.

From an code interpreter's point of view, the first one should be faster. In the second example every loop you have to access the this.data array.
In modern browsers you might have a good Just In Time compiler. If this is true, this JIT could possibly 'translate' your code in the exact same opcode.
So you have to test in different browsers by executing your code several times (I mean several thousand times) and measure the execution time.
If you don't have a JIT compiler in your browser folloding would be even faster.
var data = this.data
for(var keyA in data)
{
var content = data[keyA].content;
for(keyB in content){
alert(content[keyB].score);
}
}

Related

Is it faster to delete properties or construct a new object with only desired properties?

I have a loop being executed several million times, in NodeJS, that amongst many other things strips a few undesired properties from some objects.
I'm curious to know in general, whether it is faster to do:
undesiredPropsArray.forEach(p => delete(obj[p]))
or
var newObj = {};
Object.keys(obj).forEach(p => { if (!undesiredPropsObj[p]) newObj[p] = obj[p] });
Simply running a test isn't as simple as it sounds maybe, because the number of desired and undesired properties will vary.
If you, for a moment, assume that each of those commands take equal time to execute, then whichever task has less commands to execute will execute faster. In other words, if you have less undesired properties, compared to number of properties that you want to keep, then deleting should be faster (and vice-versa). Although, unless we're talking about huge objects processed a huge number of times, the time saved will be negligent. I think :)
You can benchmark and compare javascript code on jsperf. I did and first approach is faster as expected (aprox by 66% - this may vary)..
EDIT:
This is init code I used:
var undesiredPropsArray = [];
var undesiredPropsObj = {};
var obj = {};
for (i=0;i<10000;i++) {
obj[i] = null;
if ((i%2) === 0) {
undesiredPropsArray.push(i);
undesiredPropsObj[i] = null;
}
}

get sub array of array javascript

I have a array in javascript and I want a sub array of the array with element which are at position n*3, n=0,1,2.. for example if:
var arr = [1,2,3,4,5,6,7,8,9,10,11,12]
var subArr = [1,4,7,10]
Edit : any soln without looping.
Here's an example of a fancy way :
var brr = [1,2,3,4,5,6,7,8,9,10,11,12].filter(function(_,i){ return !(i%3) })
But a simple loop would have been as good (and would have been compatible with IE8). note that filter, even if it's not visible, does loop over the array. You can't avoid a loop (at least for an arbitrary sized array) even if you may disguise it.
Here's how you would do it with a standard loop :
var brr = [];
for (var i=0; i<arr.length; i+=3) brr.push(arr[i])
Performance is rarely a concern on such operations client side but you might find important to know that the for loop is much faster here : http://jsperf.com/looporfilter
In order to operate on a set of data of size n, m times, where m > 1, how would you avoid iteration? Really, there is no way unless you use a set of O(1) operations like this:
var arr = [1,2,3,4,5,6,7,8,9,10,11,12];
var subarr = [];
subarr.push(arr[0]);
subarr.push(arr[3]);
subarr.push(arr[6]);
subarr.push(arr[9]);
Here is a structural recursion (which can be represented by a loop, and does technically loop).
var arr = [1,2,3,4,5,6,7,8,9,10,11,12];
var subarr = [];
(function recur(n){
if( n >= arr.length ) return;
subarr.push(arr[n]);
recur(n+3);
})(0);
To note: a straight for loop will always be faster. In an expansion of #dystroy's jsperf, this recursion ran slower than the for loop, but faster than the filter. http://jsperf.com/looporfilter/2
just for kicks, i searched for a way to actually do it without a loop like the OP wanted.
without using a loop, it's tough.
the closest i could manage gets the right numbers, but converts them to Strings instead of numbers.
var r=[1,2,3,4,5,6,7,8,9,10,11,12,13,14];
alert( "".replace.call(r+",-0,-0,-0", /(\d+),\d+,?(\d+,|$)/g, "$1,")
.replace(/(,?\-0){1,4}$/g,"")
.split(",") );
//shows: 1,4,7,10,13
if you need strong numbers, it's easy, but i am not sure if adding .map(Number) after .split(",") would constitute a loop in your book, but this is the only version that actually finds the desired results without a loop.
this also only works on positive integers as coded.
again, more for fun than something i would recommend using; don't be afraid of loops...
Here's a solution with no loop:
var arr = [1,2,3,4,5,6,7,8,9,10,11,12];
// pickInterval is a function that automatically picks every "n"
// elements from an array, starting with the first element
var subArr = pickInterval( arr, 3 );
// now subArr is [1,4,7,10]
Simple, isn't it? And not a loop in sight.
Ah, but you ask, "What's the catch? You haven't implemented that pickInterval() function, have you? I bet there's a loop in it."
And you're right. Even if we write our pickInterval() function using some other function that doesn't look like a loop, that function will have a loop in it. And if that one just calls yet another function, eventually you will find a loop.
It may be turtles all the way down, but there's a loop underneath them all.
So, to implement pickInterval(), we could use either approach from #dystroy's answer. We can put the loop right inside the function:
function pickInterval( array, interval ) {
var result = [];
for( var i = 0, n = array.length; i < n; i += 3 )
result.push( array[i] );
return result;
}
Or we can use .filter():
function pickInterval( array, interval ) {
return array.filter( function( _, i ){
return !( i % 3 );
});
}
Of course there's still a loop here, down inside .filter(). It's just been hidden from us in the very same way that pickInterval() hides any loop from its caller.
And that's the real point. Use .filter(), use a for loop, use whatever you want, as long as you encapsulate it inside a function. Then the inner workings of that function don't matter so much. If you like the for loop because it's fast and easy to understand, use that. If you like the filter() version because it's interesting and elegant, use that. If you later need to use it on a very large array and it's running slow, you can replace it with the for loop version without affecting the code that uses pickInterval().
Whatever code you write for this or for something like it, don't put it inline. Make a function.

Benefits of .each() function in jQuery over traditional "for" loops

One of my colleague suggested me to use jQuery .each() function over javascript for loop to traverse through DOM elements on my page, I am not a newbie in jQuery, but never understood the real reason behind why developers tend to use .each() over for loop of javascript. Can anyone explain it to me?
If you want to iterate using a for loop, you have to increment the index:
for(var i=0; i<arr.length; ++i) {
and then you have to get the actual value using the index:
var value = arr[i];
.each does both of these for you and passes the values into a function:
$(...).each(function(i, value) {
// actual interesting part of the loop...
});
It simply saves you the boilerplate code of incrementing the index and getting the value at that index.
The variables defined in an .each function are also closed over (i.e., within a closure), so the equivalent code (considering looping and variable closure, plus setting this, as well as breaking on a false return value) might be something like:
(function() {
for(var i=0; i<arr.length; ++i) {
var ret = (function(index, value) {
// actual interesting part of the loop...
}).call(arr[i], i, arr[i]);
if(ret === false) break;
}
})();
which is quite a bit more to type.
In terms of execution performance, .each is (unsurprisingly) slower than a raw for loop, because it does much more than a raw for loop.
Its very easy to use
But it is slow as shown in this test result.
http://jsperf.com/jquery-each-vs-for-loop/214
Because it is easier & cleaner to do
$jqExpr.each(function(i, el){
/* YOUR CODE */
});
than
for(var i=0; i < $jqQExpr.length; i++){
el = $jqExp[i];
/* YOUR CODE */
}
It's slower, but more expressive (shorter) and it also sets up closures. Also, on jQuery collections it integrates well into chaining; while for plain arrays I would suggest using the native .forEach method.
There is also, for me, an important benefit closure side effect if you use each instead of for.
Consider the code below (I'm using coffeescript as I'm found of..) which alerts on all links with its href value:
$("a").each (i, e)->
href = $(e).attr('href')
$(e).on "click" alert(href)
If you "translate" it into a simple for loop like :
for e in $("a")
href = $(e).attr('href')
$(e).on "click" alert(href)
This code won't work as the href variable is not enclosed in a closure...

How to Efficiently Update Objects in Javascript

I'm working on a javascript game for fun, where I have an array of character objects. I'm periodically doing checks on fields within the objects, (like characters[i].xpos, characters[i].ypos, and so on). Is it more efficient to add a function to the prototype of the class to handle moving left and right, and call that periodically, or more efficient to have a global function that adjusts the x and y pos of the character object?
Thanks for your help guys!
Edit:
Thanks for your answers guys. I'll try to be more specific. I have one global update function that is called with an interval and has a bunch of code in it that changes the properties of an object, like:
globalupdate() {
characters[i].posx++;
characters[i].posy++;
... and more code like that
}
Would it be faster to just write a prototype function within that class and call that? Like:
globalupdate() {
characters[i].update();
}
Thanks for all the quick replies!
I have just read an article on that subject by John Resig (author of jQuery). Judging from that, the most important thing is to not have multiple timers (i.e. intervals and timeouts) because there is a potential for conflict.
So, if your global function will result in having less timers this might very well be beneficial to the overall performance.
link: http://ejohn.org/blog/how-javascript-timers-work/
Edit: Do I understand your update correctly and is this what you want to know: given a block of code,
{
object1.<key> = <value> ;
object2.<key> = <value> ;
/* ... */
objectN.<key> = <value> ;
}
and an alternative block of code,
{
object.prototype.change = function( ) { this.<key> = <value> ; } ;
list = [object1,object2,/* ... */,objectN] ;
for(i = 0 ; i < list.length ; i++) list[i].change( ) ;
}
which one would be executing faster?
As for all performance questions where it only takes 1 min to code together a test for each case, try.
I think the difference is negligble compared to the "visible" part of the update, ie updating the DOM etc. Also remember that it's probably going to be differences depending on which browser that is used.

Optimise a simple double for loop for IE

array.sort(function(left, right) {
return index(otherArray, left) < index(otherArray, right);
});
This is O(len(array) ^ 2) so for a reasonable size array of len = 1000 this takes constant * 1 million operations which easily overshoots the IE 5 million operators cap.
Thus IE throws a script is taking too long even though this is fast.
The problem is that IE does not have it's own Array.prototype.indexOf so I can't reduce the operation count down to O(len(array) and rely instead end up using a double for loop instead of a single for loop.
I considered array.join and using String.prototype.indexOf but the objects in the arrays are DOM elements and you can't convert them to a string (easily).
Telling IE users to remove this default cap is not an option.
I can think of two possible solutions to this problem: one of which will work everywhere, the other which is entirely IE-proprietary (and I expect doesn't work in IE9, but that supports Array.prototype.indexOf, so that's a non-issue).
The first, simpler, solution is to just set a property on each HTMLElement of the desired order and sort by that. If you care about the desired order persisting, you'll have to make sure the HTMLElement objects don't get garbage collected, so you'll have to keep references to them around (it's probably simplest to just create an array in the global scope for it).
The IE-only solution is to do something similar to what #maclema was proposing, using a lookup object, and HTMLElement.uniqueID:
var otherArrayLookup = {};
for (var i=0; i < otherArray.length; i++) {
otherArrayLookup[otherArray[i].uniqueID] = i;
}
array.sort(function(left, right) {
return otherArrayLookup[left.uniqueID] < otherArrayLookup[right.uniqueID];
});
You'll want to add some branches in there (don't put any within the callback function, but use different callback functions) for the Array.prototype.indexOf supported case, the HTMLElement.uniqueID supported case, and the none-of-the-above case.
You could try making an index lookup object. This should greatly increase performance too.
var otherArrayLookup = {};
for ( var i=0; i<otherArray.length; i++ ) {
otherArrayLookup[otherArray[i]] = i;
}
array.sort(function(left, right) {
return otherArrayLookup[left] < otherArrayLookup[right];
});

Categories

Resources