vscode visual studio start jshintrc es6 code all javascript jslint

javascript - visual - jshint vscode



Error JSlint ''No hacer funciones dentro de un bucle'' lleva a la pregunta sobre el Javascript mismo (4)

¿Un intérprete de JavaScript realmente crearía una instancia de la función por iteración?

Tiene que hacerlo porque no sabe si el objeto de función se modificará en otro lugar. Recuerde que las funciones son objetos estándar de JavaScript, por lo que pueden tener propiedades como cualquier otro objeto. Cuando haces esto:

card = $(''<div>'').bind(''isPopulated'', function (ev) { ... })

para todo lo que sabes, bind podría modificar el objeto, por ejemplo:

function bind(str, fn) { fn.foo = str; }

Claramente, esto daría como resultado un comportamiento incorrecto si el objeto de función se compartiera en todas las iteraciones.

Tengo un código que invoca funciones anónimas dentro de un bucle, algo así como este pseudo ejemplo:

for (i = 0; i < numCards; i = i + 1) { card = $(''<div>'').bind(''isPopulated'', function (ev) { var card = $(ev.currentTarget); ....

JSLint informa del error ''No hacer funciones dentro de un bucle''. Me gusta mantener mi código JSLint limpio. Sé que puedo mover la función anónima fuera del ciclo e invocarla como una función nombrada. Aparte de eso, esta es mi pregunta:

¿Un intérprete de JavaScript realmente crearía una instancia de la función por iteración? ¿O existe realmente solo una instancia de función "compilada" y el mismo código se ejecuta de forma repetida? Es decir, ¿la "sugerencia" de JSLint para mover la función fuera del ciclo de hecho afecta la eficiencia del código?


Boo a JSLint. Es como un instrumento contundente en la cabeza. Se crea un nuevo objeto de función cada vez function se encuentra una function (es una declaración / expresión, no una declaración - edición: esta es una mentira blanca. Consulte las respuestas de TJ Crowders ). Por lo general, esto se hace en un ciclo para un cierre, etc. El problema más grande es crear cierres falsos .

Por ejemplo:

for (var i = 0; i < 10; i++) { setTimeout(function () { alert(i) }, 10) }

Provocará un comportamiento "extraño". Esto no es un problema con "crear una función en un bucle sino hasta no entender las reglas que JS usa para los ámbitos de variables y cierres (las variables no están vinculadas en cierres, ámbitos - contextos de ejecución - sí lo son).

Sin embargo, es posible que desee crear un cierre en una función. Considere este código menos sorprendente:

for (var i = 0; i < 10; i++) { setTimeout((function (_i) { return function () { alert(_i) } })(i), 10) }

¡Oh no! ¡Todavía creé una función!


El intérprete puede crear un nuevo objeto de función con cada iteración, aunque solo sea porque esa función podría ser un cierre que necesita capturar el valor actual de cualquier variable en su ámbito externo.

Es por eso que JSLint quiere asustarlo para que no cree muchas funciones anónimas en un círculo cerrado.


Parcialmente depende de si está usando una expresión de función o una declaración de función . Son cosas diferentes, ocurren en momentos diferentes y tienen un efecto diferente en el ámbito circundante. Así que comencemos con la distinción.

Una expresión de función es una function producción en la que está utilizando el resultado como un valor de la mano derecha, por ejemplo, está asignando el resultado a una variable o propiedad, o pasándolo a una función como un parámetro, etc. Estos son todos expresiones de función:

setTimeout(function() { ... }, 1000); var f = function() { ... }; var named = function bar() { ... };

(No use esa última, que se denomina expresión de función nombrada , las implementaciones tienen errores, particularmente IE ).

Por el contrario, esta es una declaración de función :

function bar() { ... }

Es independiente, no estás usando el resultado como un valor de mano derecha.

Las dos principales diferencias entre ellos:

  1. Las expresiones de funciones se evalúan donde se encuentran en el flujo del programa. Las declaraciones se evalúan cuando el control ingresa al alcance que lo contiene (por ejemplo, la función que lo contiene o el alcance global).

  2. El nombre de la función (si tiene uno) se define en el alcance que contiene una declaración de función. No es para una expresión de función (salvo errores del navegador).

Sus funciones anónimas son expresiones de función , y por lo tanto, salvo que el intérprete realice la optimización (que es libre de hacerlo), se recrearán en cada ciclo. Entonces su uso está bien si cree que las implementaciones se optimizarán, pero dividirlo en una función nombrada tiene otros beneficios y, lo que es más importante, no le cuesta nada. Además, consulte la respuesta de casablanca para obtener una nota sobre por qué el intérprete puede no ser capaz de optimizar la recreación de la función en cada iteración, dependiendo de qué tan profundamente inspeccione su código.

El problema más grande sería si utilizó una declaración de función en un bucle, el cuerpo de un condicional, etc.

function foo() { for (i = 0; i < limit; ++i) { function bar() { ... } // <== Don''t do this bar(); } }

Técnicamente, una lectura detallada de la gramática de la especificación muestra que no es válido para hacer eso, aunque prácticamente ninguna implementación en realidad lo hace cumplir. Lo que hacen las implementaciones es variado y lo mejor es mantenerse alejado de él.

Por mi dinero, lo mejor es usar una declaración de función única, como esta:

function foo() { for (i = 0; i < limit; ++i) { bar(); } function bar() { /* ...do something, possibly using ''i''... */ } }

Obtiene el mismo resultado, no hay posibilidad de que una implementación cree una nueva función en cada bucle, obtenga el beneficio de que la función tenga un nombre , y no pierda nada.