How to exclude added to Array methods from processing in "for..in" loop? (javascript)
Asked Answered
S

6

2

I've added some useful helpers to Array (such as toSource() for Opera). And now for..in returns the functions with normal properties.

I'm using for..in now, because the code is easier to read with it. And it's a native functional of js, so must be faster.

But adding type checks in loop makes it easier to use classic for(;;).

Is there any methods to avoid for..in enumerate functions ?

Cross-browser work is not very necessary (must work in Opera), but speed is important.

Thank you.


Edit:
Is there any ability to avoid for..in enumerate functions or custom properties from any Object ?

Stiff answered 27/11, 2009 at 15:59 Comment(1)
related, if not even duplicate: Javascript: hiding prototype methods in for loop?. See also this summing up answerDanutadanya
F
5

You should never use for..in loops to iterate over array elements. for..in is designed for iterating over properties, and should only be used for that, for exactly the reason you've just described. Many libraries modify array, date, etc prototypes, so you should not rely on for..in iterating just the array elements. Use the for(;;) method, it's guaranteed to do what you want. And it's no faster than a for..in loop, because it's native to javascript as well.

For more info, read about it in the prototype.js library.

Faultless answered 27/11, 2009 at 16:3 Comment(3)
Or use jQuery.each jquery-howto.blogspot.com/2009/06/…Clamworm
Thank you for answer. One of the reasons, I tried to use for..in is that I don't like to write a lot of the same code.Stiff
@HappyCoder Jquery each also use the prototype methods added, so will still having the same problem.Wendelina
A
3

Yes, but it's JavaScript 1.7+ - only. Opera only has limited JavaScript 1.7 support, which includes very basic support of destructuring assignment so this won't work in Opera but it will work in Firefox.

This implementation allows safely using for [each](item in array):

Array.prototype.__iterator__ = function (flag) {
    var len = this.length, i = 0;

    for (; i < len; i++) {
        yield flag ? i : this[i];
    }
};
Amyotonia answered 27/11, 2009 at 17:29 Comment(1)
Crescent: flag is true if the array was used in a for..in loop and false if it was used in a for each..in loop.Amyotonia
I
3

There is another option now with ES5 support, it lets you define non-enumerable properties! It should be possible (though I haven't tested) to do something like this:

Object.defineProperty( Array.prototype, "myNewMethod", {
   value: function(){},
   writable: true,
   enumerable: false, /* this controls for..in visibility */
   configurable: true
});
Ingate answered 3/1, 2012 at 23:35 Comment(0)
R
2

As others stated, you should NOT use for..in to iterate over arrays. It is slower than using a for(;;).

You should also cache the length of the array if you are concerned with performance, as:

for (var i=0, len=arr.length; i<len; i++) 
{
  ... 
}

Use only for..in to iterate over properties of objects. To exclude the inherited properties, use the hasOwnProperty() method:

for (var prop in object)
{
  // Don't include properties inherited from the prototype chain
  if (object.hasOwnProperty(prop))
  {
    ...
  }
}
Rajah answered 27/11, 2009 at 16:34 Comment(2)
Thank you. Yes, I know about "caching", but this is another thing, I don't want to write, but want to have :) Don't want to write the same code in every loop. I know, I can use something like arr.MyFor(function() {..}), but don't know, how to write it and will it be better. About .hasOwnProperty - yes, I know, but check inside the loop is the thing I want to avoid.Stiff
Hi zxcat, If you're really concerned with performance (I'm assuming that once you don't to make an extra check inside the loop), the best way to do is to write the whole loop by hand. Function calls are very expensive in JavaScript, compared to compiled languagens. Any kind of each() / myFor() function will perform MUCH SLOWER because you'll normally use 2 functions (the loop generator and the loop iterator). To avoid typing the same code every time, the best way is to use macros/templates/snippets or other features from your source code editor of choice.Rajah
D
1

What you're describing is exactly why you use

for (var i=0; i<arr.length; i++) { ... }

instead of:

for (var item in arr) { ... }

because they are different.

If you don't want all the members that you'll get in the second form and just the indexed elements then use the first form.

Dimity answered 27/11, 2009 at 16:2 Comment(2)
Thank you. I have an Array, so for(;;) works fine. But Array is with holes (e.g. a[0]=some, a[100]=other and a[1..99] not used), so checks for element existence are needed. With for..in there is no this checks, but it's returns more then I need. I want to use fast and light construction to process elements. I'm new to js, so maybe it's better to use Object instead of Array for my task)Stiff
You are welcome. >I'm new to js, so maybe it's better to use Object instead of Array for my task The thing is, Array is Object. For-in walks the Object's properties. And a Function can be a property of an Object. Just don't create holes in Arrays and you'll be fine. I recommend you to learn Javascript the right way. This will help you a lot -- crockford.com/javascriptClamworm
I
0

Edit: corrected wrong typeof usage thanks to @Bergi 's comment

good point about performance when iterating over (very) sparse arrays - I'd suggest that perhaps using isNaN(parseInt()) in the loop lets you find array elements only:

for( var propertyName in myArray){
    if( !isNaN(parseInt(propertyName)) ){ /* probably array element */ }
}

I don't know what performs better of hasOwnProperty() and the above approach though. You simply have to measure this with a very large array iterating it 10000 times or something like that. If you do some performance measurements, the results would be interesting so please share! :)

Ingate answered 6/12, 2009 at 20:9 Comment(1)
property names are always strings. Always.Danutadanya

© 2022 - 2024 — McMap. All rights reserved.