Which is faster, For Loop or .hasOwnProperty? - javascript

I was working on a project where I needed to pull a list of excluded users out of a giant list of user data. It made me wonder if it is faster to use a double for loop with excluded id's in an array. Or if putting the id's in object properties and using .hasOwnProperty() is faster.
var mainList = LARGE JSON OBJECT OF DATA.
var eArray = ["123456","234567","345678","456789","012345"];
var eObject = {"123456":"0","234567":"0","345678":"0","456789":"0","012345":"0"};
Using the Double For Loop Approach:
for(i=0; i < mainList.length; i++){
for(j=0; j < eArray.length; j++){
if(mainList[i]['id'] === eArray[j]){
//Do Something
}
}
}
Using the .hasOwnProperty() Approach:
for(i=0; i < mainList.length; i++){
if(eObject.hasOwnProperty(mainList[i]['id'])){
//Do Something
}
}
I realize there are other ways to make the loops faster, like storing lengths in variables. I've tried to simplify this.
Thanks for any information.

You've missed out on a third, faster alternative. Provided you haven't been tinkering with the Object.prototype in any way, and the ID's are unlikely to be prototype values (like valueOf and the like), you could simply use a for loop like so:
for(var i=0; i < mainList.length; i++)
{
if (eObject[mainList[i].id] !== undefined)
{//or typeof eObject[mainList[i].id] !== 'undefined'
//do something
}
}
Check the updated JSPref, it's the fastest way by far (57,252,850 ops/sec vs 17,503,538 ops/sec for the double loop)

If you think about it, it would make sense that the .hasOwnProperty() approach would be faster because it uses only 1 for loop.
WRONG
I was actually a little surprised. I was expecting the double loop to be slower. But I guess you can't under estimate the speed of a for loop.
Double Loop
While this to me would seem like the slowest, this actually ended up being the fastest benching at 7,291,083 ops/sec
.hasOwnProperty()
I can see how this would be slower because functions are slower than statements. This benches at 1,730,588 ops/sec
if..in
#Geuis answer included the if..in statement and thought I would test the speed of that which would seem the fastest but benching at 2,715,091 ops/sec it still doesn't beat the for loops.
Conclusion
For loops are fast. The double loops runs more than 4 times faster than using .hasOwnProperty() and almost 3 times faster than using the if..in condition. However, the performance is not really noticeable; so is speed really that important that you have the need to complicate things. In my opinion the if..in method is the way to go.
Test this yourself in your browser. I was using Google Chrome 28.
Update
It is important to note that using an for..in declaration will give you the best performance.

Edit to show the proper code for future internet traversers: Visit http://jsperf.com/stackoverflow-for-vs-hasownproperty/5 for the comparison
var testVal = 'BigBrownFox',
arr = [1,4,'asd','BigBrownFox',9];
if( arr.indexOf('testVal') > -1 ){
//do something
}
For testing an array of values for existence in another array:
var testVal = ['BigBrownFox'],
arr = [1,4,'asd','BigBrownFox',9];
for(var i=0, len=testVal.length; i<len; i++){
if( arr.indexOf(testVal[i]) > -1 ){
//do something
}
}
Actually, your approach in both cases is slightly off.
If are using an array, just use the indexOf function. If the testing value exists, it will return its index. Otherwise it's -1 if not found. No loop is needed at all.
In the case of an object, you don't use .hasOwnProperty. Yeah, it does what you want but its overcomplicated and slower because you're doing a function call.
Just use
var eObject = {"123456":"0","234567":"0","345678":"0","456789":"0","012345":"0"};
if( '234567' in eObject ){ //do something }
Hope this helps.

in chrome the fastest loop is for
in older/other browsers the fastest one is the while-- loop.
especially if you cache the length.(very important if the mainList is big)
as i see you have only strings in eObject i also suggest to use (eObject[mainList[i].id])
which is faster than (eObject[mainList[i].id] !== undefined)
var i=mainList.length;
while(i--){
if (eObject[mainList[i].id]) {
//do something
}
}

Related

Best practice: Javascript for loop

What is the best practice for writing a JavaScript for loop?
I started out writing it like this:
for(var i = 0; i < array.length; i++){
//do stuff
}
But then I found that calculating the length on each pass is not ideal, so it should be more like:
var len = array.length;
for(var i = 0; i < len; i++){
//do stuff
}
But then the loop is faster if you decrease rather than increase:
var lenArr = array.length - 1;
for(var len = lenArr; len > 0; len--){
//do stuff
}
This kind of loop however doesn't really work if you want to break just one loop in a cluster of nested loops, so you should therefore get into the habit of using labels:
var lenArr = array.length - 1;
var lenArr2 = array2.length - 1;
loop1: for(var len = lenArr; len > 0; len--){
loop2: for(var len2 = lenArr2; len2 > 0; len2--){
//do stuff
break loop2;
}
}
Is there something else that will need to change, or is this the best practice for writing for loops in JavaScript?
IF you have array than make use of forEach
array.forEach(ele=> {
});
that way you can keep code clean and easy to understand and dont have to do length related code.
Break is not going to work with forEach but you can write return for coming out of forEach like
array.forEach(ele=> {
ele.array.forEach(ele=> {
//do stuff
return;
});
});
Note:
for loop is faster.
forEach is slower, but better fits functional programming paradigms.
Answer is based on title of question : Best Practice that why given suggestion to make use of forEach over for.
Actually, i prefer for...of as you can still break and its much less typing and its definetly more readable:
for(const el of array)
If you need indices too:
for(const [index, el] of array.entries())
Or if you need to iterate from back to front:
for(const el of array.reverse())
Concerning saving array.length: Even though in the early days of JavaScript it made a difference to save the .length value in a variable, modern JavaScript engines will run the for loop just as fast if you write it as in the first version.
Iterating backward is also not guaranteed to run faster on modern engines. There is also the consideration that CPUs are optimised to anticipate forward memory references, although this will only be relevant when the JS engine has decided to store the array as a contiguous block of memory.
As for the use of labels: most would not consider this best practice. Where the previous optimisation (concerning .length) concerns all iterations of the loop, this issue only applies to a single exit out of both loops. Whatever solution you use, it represents constant time, and could not be a determining factor in the overall performance of the loop.
So certainly in this case, I would go with good coding habits over tiny optimisation considerations. When you want to exit just the current loop, a single break is enough.
If you want to exit quickly from nested loops, then consider placing them in a function, so you can use return:
function performNestedLoop(array, array2) {
for(let i = 0; i < array.length; i++){
for(var j = 0; j < array2.length; j++){
//dostuff
if (exitCondition) return;
}
}
}
As to best practice: this really depends on what you need to achieve. There are several array methods that provide iteration, like forEach, map, reduce, reduceRight, filter, some, every, find, findIndex, includes,... each with their purpose. If they fit the purpose, then go with them. If you don't need the index, but just the value, then use for..of. If you really need every speck of optimatisation, then the old fashioned for loop is a likely winner.
You can use Array.forEach
Advantage of using forEach are as follows
Provides functional scoping, and whenever you need to perform some async function in the loop, you will not be required to created any IIFE
It keeps your code tidy and more contextual
Sample Code
arr.forEach(function(item, index){
// do stuff
});

Javascript for loop syntax

As javascript developers we all have to write a lot of for loops. Before a couple of months I saw an alternative syntax, which I really liked. However, I'm now interested, is there any other nice way.
Let's say that I have an array of data representing users in a system. What I did before is:
var users = [
{ name: "A"},
{ name: "B"},
{ name: "C"},
{ name: "D"},
{ name: "E"}
];
var numOfUsers = users.length;
for(var i=0; i<numOfUsers; i++) {
var user = users[i];
// ...
}
There is one additional row var user = users[i];. Normally I feel more comfortable if I have user instead of users[i]. So, the new way:
for(var i=0; user=users[i]; i++) {
// ...
}
I'm also wondering if the second approach produces problems in some of the browsers. One of my colleagues reported that this syntax is a little bit buggy under IE.
Edit:
Thankfully, the answers below pointed me out to the right direction. If some of the elements of the array is falsy then the loop will stop. There is some kind of solution:
for(var i=0; typeof (user=users[i]) !== "undefined"; i++) {
// ...
}
But that's too much for me. So, I guess that I'll use this syntax only when I'm 100% sure that all the elements are truly (which means never :)).
In your “new” approach, you don’t need numOfUsers any more.
As for the potential problems: This approach relies on all users[i] having values evaluating to true for the loop to continue (and user becoming undefined, equal to false and therefor ending the loop after the last user is processed) – but sometimes you might have data where not every record evaluates to true, but “false-y” values might also occur in the data – and in that case, this approach of course fails.
The problem with this approach:
for(var i=0; user=users[i]; i++) {
// ...
}
...is that it assumes user won't be "falsey" (0, "", null, undefined, NaN, or of course false) until you've gone past the end of the array. So it'll work well with an array of non-null object references, but if you then get in the habit of using it, it will bite you when you have an array of numbers, or strings, or such.
The other reason not to declare variables within the for construct is that it's misleading: Those variables are not scoped to the for loop, they're function-wide. (JavaScript's var doesn't have block scope, only function or global scope; ES6 will get let which will have block scope.)
On modern JavaScript engines (or with an "ES5 shim"), you can of course do this:
users.forEach(function(user) {
// ...
});
...which has the advantage of brevity and not having to declare i or numUsers or even user (since it's an argument to the iteration callback, and nicely scoped to that). If you're worried about the runtime cost of doing a function call for each entry, don't be. It'll be washed out by whatever actual work you're doing in the function.
I'm amazed if the second syntax works at all your middle operation should evaluate to true for each loop you want to complete and false as soon as you want to be done looping. As for any issues with your first for loop, a JavaScript is function scoped so that inner var statement will still leak to the containing function (as well as that i). This is different than most other languages that have block scoping. It's not so much of a problem but something to keep in mind if you are debugging.
If you are already using jQuery, you can use the jQuery.each function to loop over your arrays.
In any case you can look at the source code of that function and copy the relevant parts for your own foreach function: http://james.padolsey.com/jquery/#v=1.10.2&fn=jQuery.each

Is this usage of for .. in acceptable?

I'd like to do the same thing using several strings. I'd like to do it like this:
names = ["NOTE", "REPLICA", "HINT", "VIEW"];
for (name in names) {
name = names[name];
//do stuff
}
Then I read this. Is it still OK?
It's better to go through an array using a number:
var i = 0;
for(i=0;i<names.length;i++){
...
}
the article you link to already mentioned that any other object properties including stuff on Array.prototype or Object.prototype will show up in for ... in another reason not to use it is that for .. in for Array's is slower.
That article does mention an edge case where for ... in could be faster when the lenght of the array is big but only a couple of items are set. In that case I guess you can use for ... in with hasOwnProperty and checking if the property is a number:
var stuff, index;
stuff = [];
stuff[0] = "zero";
stuff[9999] = "nine thousand nine hundred and ninety-nine";
stuff.name = "foo";
for (index in stuff)
{
if (stuff.hasOwnProperty(index) && String(Number(index)) === index) {
console.log("stuff[" + index + "] = " + stuff[index]);
}
}
It's a lot slower than just using a for loop.
Around 86% slower in my browser (Google Chrome 28.0.1500.72).
Check out this benchmark I made.
While for..in loops only ran at 110,772 ops/sec (still fast), for loops ran at 791,792 ops/sec
I typically use for..in loops with objects. I believe that's what they are actually for.

Javascript optimization accessing an object in an array though a loop compared to a hash table

I have an array of elements like this:
myArray = [{name:'john',age:25},
{name:'marta',age:20},
{name:'pedro',age:22}]
My program has to access an object by it's name several times a second. I defined this function:
function getPersonByName(name){
for (var i=0; i<myArray.length; ++i)
if (myArray[i].name == name)
return myArray[i]
}
var john = getPersonByName('john');
But that loop running everytime seems inneficient. I could instead create a hash table associating the objects, and keep it updated:
var hash = {john:myArray[0], marta:myArray[1], pedro:myArray[2]}
var john = hash["john"]
But I don't know how the javascript's hash access is defined, so, is the second method actually faster?
The easiest way to implement this would be to cache the result of the function as explained by John Resig at learning advanced javascript
Your function would look something like this
function getPersonByName(name){
if (getPersonByName.cache[name]) {
return getPersonByName.cache[name];
} else {
for (var i=0; i<myArray.length; ++i)
if (myArray[i].name == name) {
getElements.cache[name] = myArray[i];
return getPersonByName.cache[name];
}
}
}
getPersonByName.cache = {};
var john = getPersonByName('john');
John Resig's stats from a few years ago recorded a performance increase of about 7 times using this method rather using direct DOM access, which is a technique that is integrated a lot in the JQuery library.
Performance tests for different ways to loop through an array are available on jsPerf
According to these benchmarks, you would get a better performance with:
function getPersonByName(name){
for (var i<myArray.length; i--;)
if (myArray[i].name == name)
return myArray[i]
}
There may be an extra benefit from storing myArray[i] in a variable to avoid to have to look it up multiple times. Just be careful to declare that variable outside of the loop.
function getPersonByName(name){
var obj;
for (var i<myArray.length; i--;)
obj = myArray[i];
if (obj.name == name)
return obj;
}
Another benchmark on jsPerf suggests that array is faster than object.
None of the benchmarks quite replicate your use. You could create a custom test on jsPerf. If you don't want to register there, you can use the quickbenchmark demo on jsdoit or download one of the many performance/benchmarking javascript libraries. Run a search for benchmark on github to locate them.

Number of elements in a javascript object

Is there a way to get (from somewhere) the number of elements in a Javascript object?? (i.e. constant-time complexity).
I can't find a property or method that retrieves that information. So far I can only think of doing an iteration through the whole collection, but that's linear time.
It's strange there is no direct access to the size of the object, don't you think.
EDIT:
I'm talking about the Object object (not objects in general):
var obj = new Object ;
Although JS implementations might keep track of such a value internally, there's no standard way to get it.
In the past, Mozilla's Javascript variant exposed the non-standard __count__, but it has been removed with version 1.8.5.
For cross-browser scripting you're stuck with explicitly iterating over the properties and checking hasOwnProperty():
function countProperties(obj) {
var count = 0;
for(var prop in obj) {
if(obj.hasOwnProperty(prop))
++count;
}
return count;
}
In case of ECMAScript 5 capable implementations, this can also be written as (Kudos to Avi Flax)
function countProperties(obj) {
return Object.keys(obj).length;
}
Keep in mind that you'll also miss properties which aren't enumerable (eg an array's length).
If you're using a framework like jQuery, Prototype, Mootools, $whatever-the-newest-hype, check if they come with their own collections API, which might be a better solution to your problem than using native JS objects.
To do this in any ES5-compatible environment
Object.keys(obj).length
(Browser support from here)
(Doc on Object.keys here, includes method you can add to non-ECMA5 browsers)
if you are already using jQuery in your build just do this:
$(yourObject).length
It works nicely for me on objects, and I already had jQuery as a dependancy.
function count(){
var c= 0;
for(var p in this) if(this.hasOwnProperty(p))++c;
return c;
}
var O={a: 1, b: 2, c: 3};
count.call(O);
AFAIK, there is no way to do this reliably, unless you switch to an array. Which honestly, doesn't seem strange - it's seems pretty straight forward to me that arrays are countable, and objects aren't.
Probably the closest you'll get is something like this
// Monkey patching on purpose to make a point
Object.prototype.length = function()
{
var i = 0;
for ( var p in this ) i++;
return i;
}
alert( {foo:"bar", bar: "baz"}.length() ); // alerts 3
But this creates problems, or at least questions. All user-created properties are counted, including the _length function itself! And while in this simple example you could avoid it by just using a normal function, that doesn't mean you can stop other scripts from doing this. so what do you do? Ignore function properties?
Object.prototype.length = function()
{
var i = 0;
for ( var p in this )
{
if ( 'function' == typeof this[p] ) continue;
i++;
}
return i;
}
alert( {foo:"bar", bar: "baz"}.length() ); // alerts 2
In the end, I think you should probably ditch the idea of making your objects countable and figure out another way to do whatever it is you're doing.
The concept of number/length/dimensionality doesn't really make sense for an Object, and needing it suggests you really want an Array to me.
Edit: Pointed out to me that you want an O(1) for this. To the best of my knowledge no such way exists I'm afraid.
With jquery :
$(parent)[0].childElementCount

Categories