14

I got this error and dont know what could be the cause. Any idea?

Problem at line 2127 character 18: Bad for in variable 'sport'. for (sport in sugested_sports)

                // make array
        var sugested_sports = data.split(",");

            // pre build DIV
        var sporty_items = '';
        for (sport in sugested_sports)
        {
            if  (sugested_sports.hasOwnProperty(sport)) {
                sporty_items += '<a href="#'+identifier[1]+'">'+sugested_sports[sport]+'</a>';
            }
        }
            // insert DIV
        DIVsuggestions.html(sporty_items);

thx alot.

Björn
  • 12,587
  • 12
  • 51
  • 70
  • 5
    JSLint may not suggest you this, but I will, to *iterate* an array object (or an array-like object), I always strongly recommend to use a plain `for` loop, the `for-in` statement is meant to be used to *enumerate* object properties, with this statement, even if you use the `hasOwnProperty` check to avoid enumerating properties on the prototype chain, the order of iteration is *not guaranteed* by the spec, it can be arbitrary, so the loop may not visit elements in the numeric order. See also: [Enumeration Vs. Iteration](http://bit.ly/9GPWDY) – Christian C. Salvadó May 22 '10 at 04:05
  • @CMS that link went bad, thanks for the tip though, I had this issue as well. – Jordan May 30 '12 at 22:20
  • @Jordan, the page was saved by archive.org, you can see it [here](http://web.archive.org/web/20101213150231/http://dhtmlkitchen.com/?category=/JavaScript/&date=2007/10/21/&entry=Iteration-Enumeration-Primitives-and-Objects). – Christian C. Salvadó May 30 '12 at 22:58

4 Answers4

19

Try

var sport;
for (sport in sugested_sports)

This takes care of the missing variable declaration and places it outside the for loop ( see jsLint error "Cannot set property 'first' of undefined" ).

Community
  • 1
  • 1
Pointy
  • 405,095
  • 59
  • 585
  • 614
  • 6
    Declaring var here will cause another jslint error. Vars should be declared at the top of scope according to jslint i.e. global or function scope. – Christopher Hunt Dec 16 '11 at 00:23
  • 4
    If you pay attention to JSLint that's true. If you don't, it doesn't matter. – Pointy Dec 16 '11 at 04:16
17

Pointy's answer is probably the one that lint is complaining about.


As a general rule you though, you should be careful when using for (... in ...). People often confuse this construct with foreach from C#, or other similar concepts in other languages, when in fact it isn't related. The javascript for in construct iterates every member of the object -- rather than just values in a collection -- including methods and properties. This behaviour can often lead to unexpected side effects if you aren't aware of how it works beforehand.

For example:

x = ['one', 'two'];
for (var value in x) {
  alert(value);
}

That yields two alerts, the first contaning 0 and the second 1, notably the indexes of the collection.

If we change that up a bit:

x = ['one', 'two'];
x.method = function() {};
for (var value in x) {
  alert(value);
}

We end up with three alerts this time, 0, 1, and method. This is the unexpected behaviour I was referring to. It's fine to use in if you know what it does, but I've seen it catch people out on more than one occasion.

The following works with both examples:

x = ['one', 'two'];
for (var i = 0; i < x.length; i++) {
  alert(i);
}
James Gregory
  • 14,173
  • 2
  • 42
  • 60
  • +1 Couldn't agree more, in addition, the order of iteration is not guaranteed by the [language specification](http://bclary.com/2004/11/07/#a-12.6.4), the properties (array indexes) may not visited in the numeric order, and also, if the `Array.prototype` object is extended (like [some libraries](http://mootools.net/docs/core/Native/Array) still do), those properties will be also enumerated... – Christian C. Salvadó May 22 '10 at 04:09
3

All the error means in JSHint/JSLint is that you didn't declare your key/iterator variable. As @Christopher suggests, JSLint wants you to declare it at the top of its scope (google JavaScript hoisting for more on hoisting, like this link):

/*global data, identifier, DIVsuggestions */
// We'll pretend all of the above were passed in from a function's parameters
// by using JSLint's "global" keyword -- now you can paste this code into
// jslint.com and have it pass muster.

// make array
var sugested_sports = data.split(","),
    sporty_items = '', // pre build DIV
    sport; // <<<<  **** DECLARE YOUR "KEY" HERE ****

for (sport in sugested_sports)
{
    if  (sugested_sports.hasOwnProperty(sport)) {
        sporty_items += '<a href="#'+identifier[1]+'">'
            +sugested_sports[sport]+'</a>';
    }
}
// insert DIV
DIVsuggestions.html(sporty_items);

This bad for in variable error here reduces to the same as a 'sport' was used before it was defined error elsewhere.


EDIT: It's worth mentioning that if your for is in an internal function, you need to declare your for in variable in that same context. JSLint will complain if you declare the for in in the parent context.

Example:

function spam(d)
{
    var fnTest, row; // `row` is defined "too early"

    fnTest = function (data) {
        for (row in data)
        {
            if (data.hasOwnProperty(row))
            {
                console.log(data.row);
            }
        }
    };

    fnTest(d);
}

To make things happy, move row into the internal function. Even though it was technically still in scope, JSLint doesn't like the "superscope" that was used before.

function spam(d)
{
    var fnTest;

    fnTest = function (data) {
        var row; // and JSLint is happy! ;^D
        for (row in data)
        {
            if (data.hasOwnProperty(row))
            {
                console.log(data.row);
            }
        }
    };

    fnTest(d);
}


By the way, James' concern is covered by the hasOwnProperty check the OP has inserted. Take out that check, and JSLint will complain, "The body of a for in should be wrapped in an if statement to filter unwanted properties from the prototype". Here's a little more on hasOwnProperty with for... in, if you're interested.
Community
  • 1
  • 1
ruffin
  • 16,507
  • 9
  • 88
  • 138
  • Anonymous downvoter want to comment? I can't fix your concern without some info (and this answer really is what JSLint is doing here, so I'm curious). – ruffin Feb 08 '14 at 14:36
2
var sugested_sports = data.split(","),
    sport,
    sport_items = '';

    for (sport in sugested_sports)
    {
        // 
    }
Swaff
  • 13,548
  • 4
  • 26
  • 26