What does the JSLint error ‘body of a for in should be wrapped in an if statement’ mean?

What does the JSLint error ‘body of a for in should be wrapped in an if statement’ mean?

I used JSLint on a JavaScript file of mine. It threw the error:
for( ind in evtListeners ) {

Problem at line 41 character 9: The body of a for in should be
wrapped in an if statement to filter unwanted
properties from the prototype.

What does this mean?

Solutions/Answers:

Solution 1:

First of all, never use a for in loop to enumerate over an array. Never. Use good old for(var i = 0; i<arr.length; i++).

The reason behind this is the following: each object in JavaScript has a special field called prototype. Everything you add to that field is going to be accessible on every object of that type. Suppose you want all arrays to have a cool new function called filter_0 that will filter zeroes out.

Array.prototype.filter_0 = function() {
    var res = [];
    for (var i = 0; i < this.length; i++) {
        if (this[i] != 0) {
            res.push(this[i]);
        }
    }
    return res;
};

console.log([0, 5, 0, 3, 0, 1, 0].filter_0());
//prints [5,3,1]

This is a standard way to extend objects and add new methods. Lots of libraries do this.
However, let’s look at how for in works now:

var listeners = ["a", "b", "c"];
for (o in listeners) {
    console.log(o);
}
//prints:
//  0
//  1
//  2
//  filter_0

Do you see? It suddenly thinks filter_0 is another array index. Of course, it is not really a numeric index, but for in enumerates through object fields, not just numeric indexes. So we’re now enumerating through every numeric index and filter_0. But filter_0 is not a field of any particular array object, every array object has this property now.

Related:  What is the order of execution in javascript promises

Luckily, all objects have a hasOwnProperty method, which checks if this field really belongs to the object itself or if it is simply inherited from the prototype chain and thus belongs to all the objects of that type.

for (o in listeners) {
    if (listeners.hasOwnProperty(o)) {
       console.log(o);
    }
}
 //prints:
 //  0
 //  1
 //  2

Note, that although this code works as expected for arrays, you should never, never, use for in and for each in for arrays. Remember that for in enumerates the fields of an object, not array indexes or values.

var listeners = ["a", "b", "c"];
listeners.happy = "Happy debugging";

for (o in listeners) {
    if (listeners.hasOwnProperty(o)) {
       console.log(o);
    }
}

 //prints:
 //  0
 //  1
 //  2
 //  happy

Solution 2:

Douglas Crockford, the author of jslint has written (and spoken) about this issue many times. There’s a section on this page of his website which covers this:

for Statement

A for class of statements should have
the following form:

for (initialization; condition; update) {
    statements
}

for (variable in object) {
    if (filter) {
        statements
    } 
}

The first form should be used with
arrays and with loops of a
predeterminable number of iterations.

The second form should be used with
objects. Be aware that members that
are added to the prototype of the
object will be included in the
enumeration. It is wise to program
defensively by using the
hasOwnProperty method to distinguish
the true members of the object:

for (variable in object) {
    if (object.hasOwnProperty(variable)) {
        statements
    } 
}

Crockford also has a video series on YUI theater where he talks about this. Crockford’s series of videos/talks about javascript are a must see if you’re even slightly serious about javascript.

Related:  Aligning multiple div boxes horizontally and vertically

Solution 3:

Bad: (jsHint will throw a error)

for (var name in item) {
    console.log(item[name]);
}

Good:

for (var name in item) {
  if (item.hasOwnProperty(name)) {
    console.log(item[name]);
  }
}

Solution 4:

Vava’s answer is on the mark. If you use jQuery, then the $.each() function takes care of this, hence it is safer to use.

$.each(evtListeners, function(index, elem) {
    // your code
});

Solution 5:

@all – everything in JavaScript is an object (), so statements like “only use this on objects” are a bit misleading. In addition JavaScript is not strongly typed so that 1 == “1” is true (although 1 === “1” is not, Crockford is big on this). When it comes to the progromatic concept of arrays in JS, typing is important in the definition.

@Brenton – No need to be a terminology dictator; “associative array”, “dictionary”, “hash”, “object”, these programming concepts all apply to one structure in JS. It is name (key, index) value pairs, where the value can be any other object (strings are objects too)

So,
new Array() is the same as []

new Object() is roughly similar to {}

var myarray = [];

Creates a structure that is an array with the restriction that all indexes (aka keys) must be a whole number. It also allows for auto assigning of new indexes via .push()

var myarray = ["one","two","three"];

Is indeed best dealt with via for(initialization;condition;update){

But what about:

var myarray = [];
myarray[100] = "foo";
myarray.push("bar");

Try this:

var myarray = [], i;
myarray[100] = "foo";
myarray.push("bar");
myarray[150] = "baz";
myarray.push("qux");
alert(myarray.length);
for(i in myarray){
    if(myarray.hasOwnProperty(i)){  
        alert(i+" : "+myarray[i]);
    }
}

Perhaps not the best usage of an array, but just an illustration that things are not always clearcut.

Related:  HTML/Javascript change div content

If you know your keys, and definitely if they are not whole numbers, your only array like structure option is the object.

var i, myarray= {
   "first":"john",
   "last":"doe",
   100:"foo",
   150:"baz"
};
for(i in myarray){
    if(myarray.hasOwnProperty(i)){  
        alert(i+" : "+myarray[i]);
    }
}

Solution 6:

Surely it’s a little extreme to say

…never use a for in loop to
enumerate over an array. Never. Use
good old for(var i = 0;
i<arr.length; i++)

?

It is worth highlighting the section in the Douglas Crockford extract

…The second form should be used with
objects…

If you require an associative array ( aka hashtable / dictionary ) where keys are named instead of numerically indexed, you will have to implement this as an object, e.g. var myAssocArray = {key1: "value1", key2: "value2"...};.

In this case myAssocArray.length will come up null (because this object doesn’t have a ‘length’ property), and your i < myAssocArray.length won’t get you very far. In addition to providing greater convenience, I would expect associative arrays to offer performance advantages in many situations, as the array keys can be useful properties (i.e. an array member’s ID property or name), meaning you don’t have to iterate through a lengthy array repeatedly evaluating if statements to find the array entry you’re after.

Anyway, thanks also for the explanation of the JSLint error messages, I will use the ‘isOwnProperty’ check now when interating through my myriad associative arrays!