2010-06-14 11 views
59

Estoy trabajando para hacer que todo nuestro código JS pase a través de jslint, a veces con muchas modificaciones con las opciones para obtener el código heredado por ahora, con la intención de corregirlo más tarde.Cómo reparar el error jslint 'No hacer funciones dentro de un bucle'?

Hay una cosa de la que jslint se queja por la que no tengo un workround. Es cuando se utilizan construcciones como esta, obtenemos el error 'No hacer funciones dentro de un bucle'.

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]); 
    } 
} 

Este bucle es parte de una implementación de JS de la herencia clásica donde las clases que se extienden las clases existentes conservan la propiedad súper de la clase extendida cuando se invoca un miembro de la clase extendida. Solo para aclarar, la implementación anterior está inspirada en este blog post de John Resig.

Pero también tenemos otras instancias de funciones creadas dentro de un bucle.

La única solución hasta el momento es excluir estos archivos JS de jslint, pero nos gustaría usar jslint para la validación de código y la comprobación de sintaxis como parte de nuestra integración continua y flujo de trabajo de compilación.

¿Existe alguna forma mejor de implementar una funcionalidad como esta o existe alguna forma de modificar código como este a través de jslint?

Respuesta

64

Douglas Crockford tiene una nueva forma idiomática de lograr lo anterior: su antigua técnica era usar una función interna para unir las variables, pero la nueva técnica utiliza un generador de funciones. Ver slide 74 in the slides to his "Function the Ultimate" talk. [Este Slideshare ya no existe]

Para los perezosos, aquí está el código:

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

¿Qué es un "generador de funciones" mejor que crear una nueva función por iteración de bucle? ¿No es lo mismo? – Gili

+11

@Gili: El código para crear la función make_handler se ejecuta en el punto que dice 'function make_handler (div_id)'. Una vez dentro del bucle 'for',' make_handler' ahora es una referencia a esa función y no se vuelve a crear para cada iteración del bucle. –

+0

¿No sería más eficiente asignar la función a var – Pascalius

7

JSLint es solo una guía, no siempre tiene que cumplir con las reglas. La cuestión es que no estás creando funciones en un bucle en el sentido al que se refiere. Solo crea sus clases una vez en su aplicación, no una y otra vez.

+1

sé que JSLint es sólo una recomendación y que está destinado a ser utilizado para detectar el mal Código JS, pero sigue siendo una buena herramienta para usar para precalificar y verificar la cordura de su código en un entorno automatizado de compilación/prueba. Cuando escribí, estoy interesado en soluciones para hacer que el código pase jslint, no evite ejecutar jslint en absoluto. – Ernelli

+11

Claro, pero si mira la respuesta a continuación, todavía está haciendo una función en un bucle. Está agregando código adicional solo para apaciguar a JSLint. ¿Por qué harías esto? –

+1

Sí, todavía realizo funciones dentro de un ciclo, mi problema fue que quería que este código pasara jslint. Ahora Skilldrick y Matt Eberts me dieron soluciones de trabajo que he probado y ahora mi código funciona y pasa jslint. Soy un programador de C/C++ antiguo, estoy acostumbrado a tener una comprobación de sintaxis como parte de la etapa de compilación. Javascript carece de compilación, jslint es lo más parecido posible al uso de un compilador c/C++ moderno con advertencias. – Ernelli

3

Basta con mover el:

bloque

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

fuera del circuito y asignarlo a una variable, como:

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

Luego, en el bucle tienen:

prototype[prop] = makeFn(...)

+1

Realmente debería aprender a formatear sus respuestas un poco mejor. Voy a editar este para ti. – TheCarver

11

(Me tropecé en esta pregunta muchos meses después de que fue publicada ...)

Si hacer una función en un bucle, se crea una instancia de una función para cada iteración del bucle. A menos que la función que se está realizando sea de hecho diferente para cada iteración, entonces use el método de poner el generador de funciones fuera del ciclo; hacerlo no es solo Vajilla, sino que permite a los demás que leen su código saber que esa era su intención .

Si la función es realmente la misma función asignada a diferentes valores en una iteración (u objetos producidos en una iteración), entonces necesita asignar la función a una variable con nombre, y usar esa instancia singular de la función en la asignación dentro del bucle:

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

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

Mayor comentario/discusión acerca de esto se hizo por otros más inteligente que yo, cuando me plantea una pregunta similar aquí en desbordamiento de pila: JSlint error 'Don't make functions within a loop.' leads to question about Javascript itself

en cuanto a JSLint: Sí, es dogmático d idiomático Dicho esto, generalmente es "correcto": descubro que muchas personas que vocalizan negativamente sobre JSLint en realidad no entienden (las sutilezas de) Javascript, que son muchas y obtusas.

+0

Agregue vars para las variables (handler, div_id). –

+1

cuando invocas el manejador (div_id) realmente ejecutas la función que mostrará la alerta. Esto sucederá cuando se ejecuta y no cuando el usuario hace clic en el div. –

+1

Si bien no hay vars declarados, esto es pseudo-código ... también cuando invocas el manejador (div_id); devuelve una función, no ejecutará la alerta hasta que se haga clic en este ejemplo. Aquí hay un ejemplo completo: http://jsfiddle.net/scottux/RWCje/ – Scottux

5

Si está utilizando jQuery, es posible que desee hacer algo como esto en un bucle:

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

Para satisfacer JSLint, una forma de evitar esto es (en jQuery 1.4.3+) para utilizar el argumento de los datos de controlador adicional para .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); 
} 
7

Literalmente, obtener torno al problema de la siguiente manera:

  1. Crear un archivo .jshintrc
  2. Agregue la siguiente línea a su archivo .jshintrc

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

+1

¡Este voto negativo es francamente absurdo! – lifebalance

+0

Veo tu punto. Si tomas la pregunta literalmente, es la respuesta correcta en realidad. El voto a la baja fue porque creo que es un mal consejo. Cualquiera que haga esta pregunta debe ser educado en su lugar. SO no me permite revertir mi voto a menos que la respuesta sea editada ... –

+0

@ThijsKoerselman Lo edité hace un momento ... – lifebalance

Cuestiones relacionadas