javascript - Vad betyder JSLint-felet 'kroppen av en for in bör vara innesluten i ett if-uttalande'?


Jag använde JSLint på en JavaScript-fil som jag har. Det gav felet:

for( ind in evtListeners ) {

Problem vid rad 41 tecken 9: Kroppen av en for-in bör omslutas av en if-sats för att filtrera oönskade egenskaper från prototypen.

Vad betyder det här?

Svar #1

Först och främst, använd aldrig en for in-loop för att räkna upp en array. Aldrig. Använd den goda gamla for(var i=0; i<arr.length; i++).

Anledningen till detta är följande: varje objekt i JavaScript har ett speciellt fält som kallas prototype. Allt du lägger till i det fältet kommer att vara tillgängligt på varje objekt av den typen. Anta att du vill att alla arrayer ska ha en cool ny funktion som kallas filter_0 som kommer att filtrera bort nollor.

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]

Detta är ett standard sätt att utöka objekt och lägga till nya metoder. Många bibliotek gör detta. Låt oss dock titta på hur for in fungerar nu:

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

Ser du? Det plötsligt tror att filter_0 är ett annat arrayindex. Självklart är det egentligen inte ett numeriskt index, men for in räknar upp genom objektfält, inte bara numeriska index. Så vi räknar nu upp varje numeriskt index och filter_0. Men filter_0 är inte ett fält i något specifikt arrayobjekt, varje arrayobjekt har nu denna egenskap.

Som tur är har alla objekt en hasOwnProperty-metod, som kontrollerar om detta fält verkligen tillhör objektet självt eller om det helt enkelt ärvts från prototypkedjan och därmed tillhör alla objekt av den typen.

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

Notera att även om denna kod fungerar som förväntat för arrayer, bör du aldrig, aldrig, använda for in och for each in för arrayer. Kom ihåg att for in enumererar fälten i ett objekt, inte arrayindex eller värden.

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

Svar #2

Douglas Crockford, författaren till jslint, har skrivit (och talat) om denna fråga många gånger. Det finns en sektion på denna sida av hans webbplats som täcker detta:

for-sats

A för en klass av uttalanden bör ha följande form:

for (initialization; condition; update) {
    statements
}

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

Den första formen bör användas med arrayer och med loopar av ett förutbestämbart antal iterationer.

Den andra formen bör användas med objekt. Var medveten om att medlemmar som läggs till i objektets prototyp kommer att inkluderas i uppräkningen. Det är klokt att programmera försiktigt genom att använda hasOwnProperty-metoden för att skilja de verkliga medlemmarna i objektet:

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

Crockford har också en videoserie om YUI-teatern där han pratar om detta. Crockfords serie av videor/föreläsningar om JavaScript är ett måste att se om du ens är lite seriös med JavaScript.

Svar #3

Dåligt: (jsHint kommer att ge ett fel)

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

Bra :

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

Relaterade artiklar