0

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...

16
  • 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. Commented Feb 11, 2014 at 9:34
  • 1
    why don't you just use 0 instead of [].length? Commented Feb 11, 2014 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. Commented Feb 11, 2014 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. Commented Feb 11, 2014 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. Commented Feb 11, 2014 at 10:00

6 Answers 6

3
var len = foo.children ? foo.children.length : 0;
for (i = 0; i < len; i++) {
    ...
}
9
  • I'd say this is a "hidden" if-statement :-) Commented Feb 11, 2014 at 9:39
  • 2
    So is ||. They're all just different types of conditional operators. Commented Feb 11, 2014 at 9:42
  • 1
    @frequent: Isn't hiding the if-statement just what you're trying to do? Commented Feb 11, 2014 at 9:44
  • @Barmar in compiled languages a logical expression can produce code that doesn't branch, which can be much more efficient. Commented Feb 11, 2014 at 9:44
  • What are you really trying to accomplish? You don't seem to be looking for the most terse code, since you wrote i += 1 rather than i++. So what is the real criteria for a good answer here? Commented Feb 11, 2014 at 9:46
2

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.

1

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")
}
1
  • @frequent I'm afraid i don't understand. Perhaps you could explain so i can improve the answer? Commented Feb 11, 2014 at 9:51
0

Another possible way:

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

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' ;)

1
  • same here. valid, but I don't want to test for object existence. Commented Feb 11, 2014 at 9:46
0

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;
        }
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.