web-dev-qa-db-fra.com

Comment corriger l'erreur jslint «Ne pas créer de fonctions dans une boucle»?

Je travaille à faire passer tout notre code JS via jslint, parfois avec beaucoup de modifications avec les options pour obtenir le code hérité pour le moment avec l'intention de le corriger correctement plus tard.

Il y a une chose pour laquelle jslint se plaint que je n'ai pas de solution de contournement. C'est lorsque vous utilisez des constructions comme celle-ci, nous obtenons l'erreur "Ne pas créer de fonctions dans une boucle".

for (prop in newObject) {
    // Check if we're overwriting an existing function
    if (typeof newObject[prop] === "function" && typeof _super[prop] === "function" &&
        fnTest.test(newObject[prop])) {
        prototype[prop] = (function(name, func) {
            return function() {
                var result, old_super;

                old_super = this._super;
                this._super = _super[name];
                result = func.apply(this, arguments);
                this._super = old_super;

                return result;
            };
        })(prop, newObject[prop]);
    }
}

Cette boucle fait partie d'une implémentation JS de l'héritage classique où les classes qui étendent les classes existantes conservent la super propriété de la classe étendue lors de l'appel d'un membre de la classe étendue. Juste pour clarifier, l'implémentation ci-dessus est inspirée de ceci blog post par John Resig.

Mais nous avons également d'autres instances de fonctions créées dans une boucle.

Jusqu'à présent, la seule solution consiste à exclure ces fichiers JS de jslint, mais nous aimerions utiliser jslint pour la validation du code et la vérification de la syntaxe dans le cadre de notre flux de travail d'intégration et de génération en continu.

Existe-t-il un meilleur moyen d'implémenter des fonctionnalités comme celle-ci ou existe-t-il un moyen de modifier le code comme celui-ci via jslint?

60
Ernelli

Douglas Crockford a une nouvelle façon idiomatique d'atteindre ce qui précède - son ancienne technique consistait à utiliser une fonction interne pour lier les variables, mais la nouvelle technique utilise un créateur de fonctions. Voir diapositive 74 dans les diapositives de son exposé "Function the Ultimate" . [Ce partage de diapositives n'existe plus]

Pour les paresseux, voici le code:

function make_handler(div_id) {
    return function () {
        alert(div_id);
    };
}
for (i ...) {
    div_id = divs[i].id;
    divs[i].onclick = make_handler(div_id);
}
65
Skilldrick

(Je suis juste tombé sur cette question plusieurs mois après sa publication ...)

Si vous créez une fonction dans une boucle, une instance d'une fonction est créée pour chaque itération de la boucle. À moins que la fonction qui est créée ne soit en fait différente pour chaque itération, utilisez la méthode pour mettre le générateur de fonctions en dehors de la boucle - ce n'est pas seulement de la vaisselle, cela permet aux autres qui lisent votre code de savoir que c'était votre intention .

Si la fonction est en fait la même fonction affectée à différentes valeurs dans une itération (ou des objets produits dans une itération), vous devez plutôt affecter la fonction à une variable nommée et utiliser cette instance singulière de la fonction en affectation dans le boucle:

handler = function (div_id) {
    return function() { alert(div_id); }
}

for (i ...) {
    div_id = divs[i].id;
    divs[i].onclick = handler(div_id);
}

De plus grands commentaires/discussions à ce sujet ont été faits par d'autres plus intelligents que moi lorsque j'ai posé une question similaire ici sur Stack Overflow: l'erreur JSlint 'Ne pas faire de fonctions dans une boucle.' Conduit à une question sur Javascript lui-même

Quant à JSLint: Oui, il est dogmatique et idiomatique. Cela dit, c'est généralement "juste" - je découvre que beaucoup de gens qui vocalisent négativement à propos de JSLint ne comprennent pas (les subtilités de) Javascript, qui sont nombreux et obtus.

12
Zhami

Littéralement, contournez le problème en procédant comme suit:

  1. Créer un .jshintrc fichier
  2. Ajoutez la ligne suivante à votre .jshintrc fichier

    {"loopfunc" : true, // tolerate functions being defined in loops }

10
lifebalance

JSLint n'est qu'un guide, vous n'avez pas toujours à respecter les règles. Le fait est que vous ne créez pas de fonctions en boucle dans le sens où elles se réfèrent. Vous ne créez vos classes qu'une seule fois dans votre application, pas maintes et maintes fois.

7
Evan Trimboli

Si vous utilisez JQuery, vous voudrez peut-être faire quelque chose comme ça en boucle:

for (var i = 0; i < 100; i++) {
  $("#button").click(function() {
    alert(i);
  });
}

Pour satisfaire JSLint, une façon de contourner ce problème est (dans JQuery 1.4.3+) d'utiliser l'argument de données de gestionnaire supplémentaire pour .click():

function new_function(e) {
  var data = e.data; // from handler
  alert(data); // do whatever
}

for (var i = 0; i < 100; i++) {
  $("#button").click(i, new_function);
}
5
jevon

Déplacez simplement votre:

(function (name, func) {...})()

bloquer hors de la boucle et l'assigner à une variable, comme:

var makeFn = function(name, func){...};

Ensuite, dans la boucle ont:

prototype[prop] = makeFn(...)

3
Matt Eberts