0

I have some javascript as shown below

for (var titleKey in data.d) {
  var title = data.d[titleKey];
}

This is actually coming back from a JQuery call to a .NET webservice but I don't believe that's related.

My loop iterates over each element in the collection correctly, it then continues through the loop one more time. The titleKey here is 'indexof' and title is 'undefined'.

This is happening in two different places in my code.

What is causing this? How can I prevent it?

Thanks in advance.

Liath
  • 9,913
  • 9
  • 51
  • 81
  • "What is causing this?" What is causing what exactly? You haven't actually explained what the problem is. – spender Nov 24 '11 at 20:21
  • 1
    Can you `console.log(data.d)` and include the output in the question? It'd be helpful to get an idea of what it contains. – davidchambers Nov 24 '11 at 20:21
  • A console of data.d gives: [0]: "Mr" [1]: "Mrs" [2]: "Miss" [3]: "Ms" [4]: "Dr" [5]: "Rev" titleKey goes from 0-5 then 'indexof' – Liath Nov 24 '11 at 20:25
  • 1
    Don't use `for ... in` to iterate over a JavaScript array. Use a standard `for` loop as suggested in some of the comments below. – davidchambers Nov 24 '11 at 20:27

5 Answers5

5

You need to exclude from the loop the properties of the prototype. The for ... in structure will loop through everything* it finds in the prototype chain, not only the properties of the child object.

for (var titleKey in data.d) {
  if (data.d.hasOwnProperty(titleKey)) {
    // own property //
  }
  else {
    // inherited property //
  }
}

From what the console log says my suspicion is that you have a library that implements the indexof for Array in its prototype.

My recommendation would be to use the correct way to walk Arrays:

for (var index = 0; index < data.d.length; index++) {...}

for in is for Objects, not Arrays. This is a common beginner mistake, where one abuses the fact that Array is derived from Object.

* See comment from davidchambers

Community
  • 1
  • 1
Alin Purcaru
  • 43,655
  • 12
  • 77
  • 90
  • 1
    "Everything it finds in the prototype chain" isn't quite correct. "Enumerable properties in the prototype chain" is more accurate. – davidchambers Nov 24 '11 at 20:29
  • @davidchambers Yeah, I know, but I didn't want to add more confusion for him. He should take it one step at a time :) – Alin Purcaru Nov 24 '11 at 20:32
  • I initially attributed the cause to the array-walking method too. However, the array does not have a (**lowercase**) `indexof` property, and its value is neither `undefined`. – Rob W Nov 24 '11 at 20:38
  • @Rob W *my suspicion is that you have a library that implements the `indexof`* <- This is what I think happened. The standard in JS >= 1.6 is the camel case `indexOf`, but that wouldn't show in a `for ... in` either because it's not marked as enumerable. – Alin Purcaru Nov 24 '11 at 20:43
  • 1
    I'm not the asker btw. +1 for having a better answer than the accepted one though. – Rob W Nov 24 '11 at 20:45
  • Appreciate the help guys - as you can probably tell I'm a JS rookie, I can usually just about get it working with a little help. Give me a good back end any day! – Liath Nov 24 '11 at 20:46
2

Javascript's "for-in" iterates through all properties of an object, and this includes method names.

Felix Rabe
  • 4,206
  • 4
  • 25
  • 34
2

Use the following loop mechanism:

for (var i = 0; i < titleKey.length; i++) {
  var title = data.d[titleKey[i]];
}

The for:in loop loops through all properties of an object, rather than just ones that are indexable.

Rich O'Kelly
  • 41,274
  • 9
  • 83
  • 114
1

If indexof comes from the prototype chain, you must use hasOwnProperty to skip over it.

for (var titleKey in data.d) {

    if (data.d.hasOwnProperty(titleKey))
    {
      var title = data.d[titleKey];
    }

}
Francis
  • 3,335
  • 20
  • 46
0

Based on the information at hand, I'd say that data.d.indexof is in fact undefined. The following is a perfectly valid data structure:

foo: 42
bar: [1, 2, 3]
baz: false
indexof: undefined

As a sanity check, try the following:

console.log(Object.prototype.hasOwnProperty.call(data.d, 'indexof'))

Edit: Now that it has become clear that the data structure is in fact an array, this answer does not solve the OP's problem. It's still valid, though, so I won't remove it.

davidchambers
  • 23,918
  • 16
  • 76
  • 105