Tenemos dos formas diferentes de hacer la expresión de funciones en JavaScript:
Expresión de función nombrada (NFE) :
var boo = function boo () {
alert(1);
};
Expresión de función anónima :
var boo = function () {
alert(1);
};
Y ambos se pueden llamar con boo();
. Realmente no puedo ver por qué / cuándo debería usar funciones anónimas y cuándo debería usar Expresiones de función con nombre. ¿Qué diferencia hay entre ellos?
javascript
function
anonymous-function
function-expression
Afshin Mehrabani
fuente
fuente
Respuestas:
En el caso de la expresión de función anónima, la función es anónima ; literalmente, no tiene nombre. La variable a la que lo está asignando tiene un nombre, pero la función no. (Actualización: Eso fue cierto a través de ES5. A partir de ES2015 [también conocido como ES6], a menudo una función creada con una expresión anónima obtiene un nombre verdadero [pero no un identificador automático], sigue leyendo ...)
Los nombres son útiles. Los nombres se pueden ver en seguimientos de pila, pilas de llamadas, listas de puntos de interrupción, etc. Los nombres son algo bueno ™.
(Solía tener que tener cuidado con las expresiones de función con nombre en versiones anteriores de IE [IE8 y anteriores], porque crearon por error dos objetos de función completamente separados en dos momentos completamente diferentes [más en el artículo de mi blog Doble toma ]. Si es necesario admite IE8 [!!], probablemente sea mejor seguir con expresiones de función anónimas o declaraciones de función , pero evite las expresiones de función con nombre).
Una cosa clave acerca de una expresión de función nombrada es que crea un identificador dentro del alcance con ese nombre para la función dentro del cuerpo de la función:
Sin embargo, a partir de ES2015, muchas expresiones de función "anónimas" crean funciones con nombres, y esto fue precedido por varios motores JavaScript modernos que son bastante inteligentes para inferir nombres a partir del contexto. En ES2015, su expresión de función anónima da como resultado una función con el nombre
boo
. Sin embargo, incluso con la semántica de ES2015 +, no se crea el identificador automático:La asignación del nombre de la función se realiza con la operación abstracta SetFunctionName utilizada en varias operaciones en la especificación.
La versión corta es básicamente cada vez que aparece una expresión de función anónima en el lado derecho de algo como una asignación o inicialización, como:
(o podría ser
let
o enconst
lugar devar
) , oo
(esos dos últimos son realmente lo mismo) , la función resultante tendrá un nombre (
boo
, en los ejemplos).Hay una excepción importante e intencionada: asignar una propiedad a un objeto existente:
Esto se debió a las preocupaciones sobre la filtración de información que surgieron cuando la nueva función estaba en proceso de ser agregada; detalles en mi respuesta a otra pregunta aquí .
fuente
new
operador (dar todos los nombres de estas funciones hace que la.constructor
propiedad sea más útil durante la depuración para averiguar qué diablos algún objeto es una instancia de), y para los literales de función pasados directamente a una función sin haber sido asignados primero a una propiedad o variable (por ejemplosetTimeout(function () {/*do stuff*/});
). Incluso Chrome muestra estos como a(anonymous function)
menos que lo ayudes nombrándolos.setTimeout
ejemplo no tomara el nombre del argumento formal declarado a favorsetTimeout
, si lo tuviera. :-) Pero sí, los NFE son definitivamente útiles si sabes que no tendrás que lidiar con navegadores antiguos que los convierten en un hash.Las funciones de nombres son útiles si necesitan referenciarse a sí mismas (por ejemplo, para llamadas recursivas). De hecho, si está pasando una expresión de función literal como un argumento directamente a otra función, esa expresión de función no puede hacer referencia directamente a sí misma en el modo estricto de ES5 a menos que tenga un nombre.
Por ejemplo, considere este código:
Sería imposible escribir este código de forma tan limpia si la expresión de función pasada
setTimeout
fuera anónima; tendríamos que asignarlo a una variable antes de lasetTimeout
llamada. De esta forma, con una expresión de función nombrada, es un poco más corta y ordenada.Históricamente, era posible escribir código como este incluso usando una expresión de función anónima, explotando
arguments.callee
...... pero
arguments.callee
está obsoleto y totalmente prohibido en el modo estricto de ES5. Por lo tanto, MDN aconseja:(énfasis mío)
fuente
Si una función se especifica como una expresión de función, se le puede dar un nombre.
Solo estará disponible dentro de la función (excepto IE8-).
Este nombre está destinado a una llamada de función recursiva confiable, incluso si está escrito en otra variable.
Además, el nombre NFE (expresión de función con nombre) PUEDE sobrescribirse con el
Object.defineProperty(...)
método de la siguiente manera:Nota: con la Declaración de función esto no se puede hacer. Este nombre de función interna "especial" se especifica sólo en la sintaxis de expresión de función.
fuente
Siempre debe usar expresiones de función con nombre , por eso:
Puede usar el nombre de esa función cuando necesite recursividad.
Las funciones anónimas no ayudan al depurar, ya que no puede ver el nombre de la función que causa problemas.
Cuando no nombra una función, más adelante es más difícil entender qué está haciendo. Darle un nombre hace que sea más fácil de entender.
Aquí, por ejemplo, debido a que la barra de nombre se usa dentro de una expresión de función, no se declara en el ámbito externo. Con expresiones de función nombradas, el nombre de la expresión de función se incluye dentro de su propio ámbito.
fuente
El uso de expresiones de función con nombre es mejor, cuando desea poder hacer referencia a la función en cuestión sin tener que depender de características obsoletas como
arguments.callee
.fuente