Rafael Baptista
Rafael Baptista

Reputation: 11499

Iterating over array of strings produces error

I pass in an array of error messages to parse. An example input would be:

"An item with this x Id already exists.
 An item with this y id already exists.
 An item with this barcode already exists.
"

That is, the string is literally each line above separated by a \n, with a final \n at the end.

function( msg )
{
  alert( "\"" + msg + "\"" );
  var aLines = msg.split( /\r?\n+/ );

  for ( var i in aLines )
  {
     if ( !aLines[i] ) { alert( "Error!" ); continue; }
     alert( i + ": \"" + aLines[i]  + "\"" );
  }
}

I split it into lines, and iterate over the lines. At index 3 there is no line and the first conditional triggers. Should that not be an empty line? e.g. ""

Then the loop actually goes one more element to 4, and shows a the contents of a function.

That is I get - five alerts:

0: "An item with this x Id already exists."
1: "An item with this y id already exists."
2: "An item with this barcode already exists."
Error!

The last one is most bizarre:

hasObject: "function(o) {
    var l = this.length + 1;
    ... more lines ...
}

I don't understand what is happening here. Why is it iterating over one more element? And why is the last element a function? And shouldn't offset 3 be an empty string? That is I should not be alerting "Error!" here.

Upvotes: 0

Views: 201

Answers (4)

TheVillageIdiot
TheVillageIdiot

Reputation: 40507

You are getting Error! in end because the splitting is giving you empty line "" and when you check for it with if(!aLines[i]) it returns true because it is empty/null/nothing. You can check it here in a fiddle, you remove the empty line from end and it does not go over array 4 times.

I have also put in following code which shows alert:

    var a="";
    if(!a){
        alert("!a");
    }

Upvotes: 0

danyim
danyim

Reputation: 1293

As jbabey said, using for .. in loops in Javascript is risky and undeterministic (random order--sometimes). You would most commonly use that for parsing through objects in associative arrays. But, if you insist on keeping the for .. in, wrap the inside of the for with an if block like such:

for (var i in aLines)
{
    if(aLines.hasOwnProperty(i))
    {
        // ... Do stuff here
    }
}

Otherwise, just change it to a classic incremental for loop to get rid of that error:

for (var i = 0; i < aLines.length; i++)
{
   if ( !aLines[i] ) { alert( "Error!" ); continue; }
   alert( i + ": \"" + aLines[i]  + "\"" );
}

Upvotes: 1

Sam Fen
Sam Fen

Reputation: 5254

You should use a regular for loop for arrays, because for-in will also return all the other property keys in the Array object. This is why you are seeing "hasObject" (and in my browser, I see a lot more after that): because your array has the function "hasObject", so when you enumerate all of Array's properties this comes up.

The correct for-loop:

  for ( var i = 0, ii = aLines.length; i<ii; i++ )
  {
    if ( !aLines[i] ) { alert( "Error!" ); continue; }
    alert( i + ": \"" + aLines[i]  + "\"" );
  }

Here is your code with the for-in loop replaced with a for loop, and it works as expected:

http://jsfiddle.net/SamFent/4rzTh/

Upvotes: 1

jbabey
jbabey

Reputation: 46647

Never loop over an array with for...in.

Iterates over the enumerable properties of an object, in arbitrary order.

Why is using "for...in" with array iteration a bad idea?

Upvotes: 5

Related Questions