En JavaScript tenemos b谩sicamente dos formas de definir funciones.

La primera y m谩s tradicional es usando la palabra clave function y otorg谩ndole un nombre a la funci贸n. Por ejemplo:

function miFunc() {
   ..... //C贸digo de la funci贸n
}

A esto se le llama declaraci贸n de funciones.

Otro modo muy habitual es, simplemente, asignar una funci贸n an贸nima a una variable para trabajar con ella, algo as铆:

var miFunc = function() {
   .... //C贸digo de la funci贸n
}

A esto se le llama expresi贸n funcional o asignaci贸n de funciones.

De hecho es posible, aunque no frecuente, hacer una combinaci贸n de ambos estilos:

var miFunc = function miFuncion(){
.... //C贸digo de la funci贸n
}

Lo que constituir铆a una asignaci贸n de funci贸n con nombre.

Todos estos casos son equivalentes, pero solo en apariencia. En todos ellos podemos llamar a la funci贸n escribiendo:

miFunc();

y aparentemente todo parece funcionar del mismo modo.

Sin embargo 驴existe alguna diferencia entre declarar una funci贸n de una forma o de otra? 驴Alguna ventaja de usar una u otra? 驴Alg煤n impacto negativo?

Vamos a verlo...

FuncionAnonima

Mi interpretaci贸n de una funci贸n an贸nima ;-)

Elevaci贸n de declaraciones

La principal diferencia entre declarar funciones de estas dos maneras tiene que ver con el efecto de hoisting, que ya expliqu茅 en su d铆a en este blog (ver enlace anterior antes de seguir leyendo si no lo conoces).

Cuando se produce hoisting en un 谩mbito, la declaraci贸n de una variable se mueve siempre al principio del bloque. Por ejemplo:

function miFunc() {
   alert(v());
   var v = function() {return 5;};
}

Este fragmento producir谩 un error porque la funci贸n no est谩 definida y 'v' se considera una variable sin inicializar, ya que es equivalente a este otro c贸digo:

function miFunc() {
   var v;
   alert(v());
   v = function() { return 5;};
}

puesto que debido al hoisting de variables, la declaraci贸n (隆pero no la asignaci贸n!) de la variable se mueve al comienzo del 谩mbito.

Solo con que movamos el alert para debajo de la declaraci贸n ya funcionar谩 como era de esperar.

Bien, si ahora hacemos lo mismo pero con una funci贸n con nombre, o sea, as铆:

function miFunc() {
   alert(v());
   function v() { return 5; };
}

驴Qu茅 resultado crees que aparecer谩 por pantalla?

En este caso funcionar谩 como se esperaba y mostrar谩 un 5, y eso que la funci贸n se define posteriormente al alert en el bloque.

El motivo es que cuando se produce el hoisting, las funciones con nombre se mueven enteras al principio del bloque, es decir, definici贸n y asignaci贸n, y por lo tanto est谩n disponibles inmediatamente en cualquier punto de su 谩mbito. El c贸digo anterior es equivalente a haber definido la funci贸n arriba del todo.

Esta es la gran diferencia existente entre funciones con nombre y an贸nimas, y hay que tenerlo muy en cuenta siempre para evitar resultados inesperados.

Pero siendo ordenados no deber铆a haber diferencia entre usar unas u otras.

Rendimiento

Respecto al rendimiento tampoco hay diferencia alguna en condiciones normales. Solo debemos tener en cuenta que cada vez que definimos una funci贸n an贸nima, aunque el c贸digo sea id茅ntico al de otra que hayamos definido antes, en realidad son dos funciones diferentes. Por lo tanto si definimos muchas funciones id茅nticas en un bucle (por ejemplo, recorremos todos los elementos de un determinado tipo en una p谩gina y les asignamos el mismo manejador para un evento), si la funci贸n va a ser id茅ntica es mejor definirla con nombre en el mismo 谩mbito y asignarla con ese nombre (puede ser tambi茅n an贸nima y asignarla a trav茅s de una misma variable: el caso es apuntar a la misma funci贸n), en lugar de usar la definici贸n de c贸digo. De esta manera tenemos una 煤nica funci贸n asignada, y no una nueva en cada asignaci贸n.

Es decir, si tenemos un c贸digo similar a este:

for(var i=0; i<colElementos.length; i++){
   colElementos[i].onclick = function { .... };
}

es m谩s eficiente hacerlo de esta manera:

var manejador = function() {...};

for(var i=0; i<colElementos.length; i++){
   colElementos[i].onclick = manejador;
}

o bien:

function manejador() {...};

for(var i=0; i<colElementos.length; i++){
   colElementos[i].onclick = manejador;
}

ya que en el primer caso en cada vuelta del bucle estamos creando una nueva funci贸n, mientras que en los otros dos casos estamos asignando la misma funci贸n una y otra vez, lo cual consume menos memoria y recursos, l贸gicamente.

Pero fij茅monos en que, en realidad, no existe diferencia alguna entre si es una funci贸n con nombre o an贸nima la que asignamos dentro del bucle, mientras no la creemos nueva una y otra vez. En los dos 煤ltimos bloques el primero usa una funci贸n an贸nima y el segundo una con nombre, y ambos son igual de eficientes y tienen el mismo rendimiento.

En realidad, en mi opini贸n, la 煤nica ventaja que tienen las funciones con nombre o declaradas frente a las asignadas es que es m谩s f谩cil utilizarlas en recursi贸n.

Test de conocimientos

De acuerdo. Ahora que tenemos claro el concepto, vamos a ver si lo hemos entendido bien.

Consideremos el siguiente fragmento de c贸digo:

function func1(){
    function a(){
        return 5;
    }
    return a();
    function a(){
        return 10;
    }
}

console.log(func1());

驴Qu茅 resultado crees que se mostrar谩 por consola? 驴5 o 10?

....... (pi茅nsalo bien antes de contestar)

Si has contestado 5, est谩s en un error. El motivo es que, como hemos visto, la definici贸n y asignaci贸n de las funciones con nombre sufren hoisting dentro de su 谩mbito, es decir, se suben al principio del 谩mbito. Por ello, el c贸digo anterior es equivalente al siguiente:

function func1(){
    function a(){
        return 5;
    }
    function a(){
        return 10;
    }
    return a();
}

console.log(func1());

Es decir, aunque la segunda (re)definici贸n de la funci贸n a se hace despu茅s de la llamada a return a(); en realidad es como si se hubiera definido antes, y por lo tanto la que prevalece es la 煤ltima, la segunda, y se devuelve un 10.

Consideremos ahora un c贸digo muy parecido pero usando asignaci贸n de funciones o funciones an贸nimas:

function func1(){
    var a = function(){
        return 5;
    }
    return a();
    var a = function(){
        return 10;
    }
}

console.log(func1());

驴Cu谩l ser谩 ahora el resultado?

......

Ahora el resultado ser谩 5. El motivo es que el hoisting en este caso lo sufre la declaraci贸n de las variables, pero no su asignaci贸n. Es decir, el c贸digo es equivalente al siguiente:

function func1(){
    var a;
    a = function(){
        return 5;
    }
    return a();
    a = function(){
        return 10;
    }
}

console.log(func1());

Solamente sube al principio del 谩mbito la declaraci贸n de la variable, quedando las asignaciones en el sitio concreto del c贸digo donde las hemos hecho. Por ello la segunda asignaci贸n nunca llega a producirse, pues antes ya salimos de la funci贸n con el return a();.

En resumen

Estas distinciones pueden parecer una cuesti贸n te贸rica sin importancia, pero en realidad es indispensable tener claros los conceptos y este tipo de situaciones. De no ser as铆 es mas que probable que nuestro c贸digo en alguna ocasi贸n tenga problemas y no sepamos de d贸nde vienen, ya que no es una cuesti贸n obvia ni tenemos forma de ver esa "reorganizaci贸n interna" del c贸digo que realiza el int茅rprete de JavaScript. Los programadores m谩s noveles suelen tener dificultades con esto casi siempre.

隆Espero que te resulte util! Y ya sabes, si quieres aprender JavaScript a fondo y teni茅ndome a mi para contestarte todas tus dudas, tengo estos dos estupendos cursos on-line:

💪🏻 驴Este post te ha ayudado?, 驴has aprendido algo nuevo?
Pues NO te pido que me invites a un caf茅... Te pido algo m谩s f谩cil y mucho mejor