Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I want to loop over an array called children which may or may not be defined.

Currently I'm doing this:

var i;
var foo = {/*"children": ["1","2","3","4"]*/};


for (i = 0; i < [foo.children || []][0]. length; i += 1) {
   console.log("hello")
}

This works correctly, because in case children is undefined, [foo.children || []][0] ends up being [[]] whose first element is an empty array [].

Question:
Is there any way to leave away the outer array?

I don't want to use an if-clause testing for children, just modify the array.

One way would be:

for (i = 0; i < foo.children.length || [].length; i += 1) {
   console.log("hello")
}

but I'm looking for other alternatives if exist.

Thanks

EDIT: Here is a jsperf on all variants. Interesting...

share|improve this question
1  
why don't you want to use an if clause? That would be the normal way, unless you're trying to write deliberately obfuscated code. –  Alnitak Feb 11 at 9:34
1  
why don't you just use 0 instead of [].length? –  Jokey Feb 11 at 9:35
3  
@frequent if you're having to test it that often you should consider whether the correct design is for children to default to an empty array instead of not existing at all. –  Alnitak Feb 11 at 9:36
1  
@Alnitak Well, it will also make the code easier to understand, which is more important. Although if he's deliberately trying to obfuscate, I guess that would be counterproductive. –  Barmar Feb 11 at 9:43
1  
@frequent no, I meant that I would refactor the length expression out of the for loop, into its own variable. This avoids re-evaluating that expression for each iteration. –  Alnitak Feb 11 at 10:00

6 Answers 6

up vote 3 down vote accepted
var len = foo.children ? foo.children.length : 0;
for (i = 0; i < len; i++) {
    ...
}
share|improve this answer
    
I'd say this is a "hidden" if-statement :-) –  frequent Feb 11 at 9:39
2  
So is ||. They're all just different types of conditional operators. –  Barmar Feb 11 at 9:42
    
mh... now that got me thinking... –  frequent Feb 11 at 9:43
1  
@frequent: Isn't hiding the if-statement just what you're trying to do? –  Bergi Feb 11 at 9:44
    
@Barmar in compiled languages a logical expression can produce code that doesn't branch, which can be much more efficient. –  Alnitak Feb 11 at 9:44

Use parenthesis instead of that one-item-array:

for (i = 0; i < (foo.children || []).length; i += 1) {

or move it further outside:

for (i = 0; foo.children && i < foo.children.length; i += 1) {

which is very near to

if (foo.children) for (i = 0; i < foo.children.length; i += 1) {

which would indeed be the cleanest way. There's nothing wrong with an if-statement.

share|improve this answer

EDIT: According to comments on other answers the OP wants terse, but jsLint appropriate code. Here it is:

var i, c, foo = {}, console; 

for (i = 0, c = foo.children; i < (c && c.length); i += 1) {
    console.log("hello");
}

I will leave the other possibilitis here for people who don't have as strict requirements as the OP does.


You can use the && operator:

for (i = 0; i < (foo && foo.children && foo.children.length); i += 1) {
   console.log("hello")
}

If there is a chance that foo is not defined at all, then you need something slightly worse:

for (i = 0; i < ((typeof foo === 'object') && foo.children && foo.children.length); i += 1) {
   console.log("hello")
}

Or if you're sure that foo is an object, you can skip the first check:

for (i = 0; i < (foo.children && foo.children.length); i += 1) {
   console.log("hello")
}
share|improve this answer
    
too many tests for me to start the loop. –  frequent Feb 11 at 9:47
    
@frequent I'm afraid i don't understand. Perhaps you could explain so i can improve the answer? –  Tibos Feb 11 at 9:51
    
thanks for update –  frequent Feb 11 at 10:00

Another possible way:

for (i = 0; foo.children && i < foo.children.length; i += 1)
share|improve this answer
    
ok. but I don't want to test for object existence. –  frequent Feb 11 at 9:46

You could add a condition checking the existence of the array to your for loop like this:

for (i = 0; (typeof foo.children != 'undefined') && (i < foo.children.length); i++) {
  // do something
}

/edit: OK, others were a bit faster than me, and foo.children is a nice alternative to typeof foo.children != 'undefined' ;)

share|improve this answer
    
same here. valid, but I don't want to test for object existence. –  frequent Feb 11 at 9:46

Why not using a function to hide all these dirty statements?

function each(array, fn) {
    if (array) {
        var i = -1;
        while (++i < array.length) {
            if (fn(array[i]) === false) return;
        }
    }
}
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.