JavaScript Función anónima


Ejemplo

Definiendo una función anónima

Cuando se define una función, a menudo se le asigna un nombre y luego se invoca con ese nombre, de esta manera:

foo();

function foo(){
    // ...
}

Cuando define una función de esta manera, el tiempo de ejecución de Javascript almacena su función en la memoria y luego crea una referencia a esa función, utilizando el nombre que le ha asignado. Ese nombre es entonces accesible dentro del alcance actual. Esta puede ser una forma muy conveniente de crear una función, pero Javascript no requiere que asigne un nombre a una función. Lo siguiente también es perfectamente legal:

function() {
    // ...
}

Cuando una función se define sin un nombre, se conoce como una función anónima. La función se almacena en la memoria, pero el tiempo de ejecución no crea automáticamente una referencia a la misma para usted. A primera vista, puede parecer que tal cosa no tendría ningún uso, pero hay varios escenarios donde las funciones anónimas son muy convenientes.

Asignar una función anónima a una variable

Un uso muy común de las funciones anónimas es asignarlas a una variable:

var foo = function(){ /*...*/ };

foo();

Este uso de funciones anónimas se trata con más detalle en Funciones como una variable

Suministro de una función anónima como un parámetro a otra función

Algunas funciones pueden aceptar una referencia a una función como parámetro. A veces, se hace referencia a ellas como "inyecciones de dependencia" o "devoluciones de llamada", ya que permite que la función de su llamada "devuelva la llamada" a su código, lo que le da la oportunidad de cambiar la forma en que se comporta la función llamada. Por ejemplo, la función de mapa del objeto Array le permite iterar sobre cada elemento de una matriz, luego construir una nueva matriz aplicando una función de transformación a cada elemento.

var nums = [0,1,2];
var doubledNums = nums.map( function(element){ return element * 2; } ); // [0,2,4]

Sería tedioso, descuidado e innecesario crear una función nombrada, que saturaría su alcance con una función solo necesaria en este lugar y rompería el flujo natural y la lectura de su código (un colega tendría que dejar este código para encontrar su función para entender lo que está pasando).

Devolviendo una función anónima de otra función

A veces es útil devolver una función como resultado de otra función. Por ejemplo:

var hash = getHashFunction( 'sha1' );
var hashValue = hash( 'Secret Value' );

function getHashFunction( algorithm ){

    if ( algorithm === 'sha1' ) return function( value ){ /*...*/ };
    else if ( algorithm === 'md5' ) return function( value ){ /*...*/ };

}

Invocando inmediatamente una función anónima

A diferencia de muchos otros idiomas, el alcance en Javascript es de nivel de función, no de nivel de bloque. (Ver Función de alcance ). En algunos casos, sin embargo, es necesario crear un nuevo alcance. Por ejemplo, es común crear un nuevo ámbito cuando se agrega código a través de una etiqueta <script> , en lugar de permitir que los nombres de las variables se definan en el alcance global (lo que corre el riesgo de que otros scripts colisionen con sus nombres de variables). Un método común para manejar esta situación es definir una nueva función anónima e invocarla inmediatamente, ocultando de manera segura las variables dentro del alcance de la función anónima y sin hacer que su código sea accesible a terceros a través de un nombre de función filtrado. Por ejemplo:

<!-- My Script -->
<script>
function initialize(){
    // foo is safely hidden within initialize, but...
    var foo = '';
}

// ...my initialize function is now accessible from global scope.
// There's a risk someone could call it again, probably by accident.
initialize();
</script>

<script>
// Using an anonymous function, and then immediately
// invoking it, hides my foo variable and guarantees
// no one else can call it a second time.
(function(){
    var foo = '';
}()) // <--- the parentheses invokes the function immediately
</script>

Funciones anónimas autorreferenciales

A veces es útil que una función anónima pueda referirse a sí misma. Por ejemplo, la función puede necesitar llamarse de forma recursiva o agregar propiedades a sí misma. Sin embargo, si la función es anónima, esto puede ser muy difícil ya que requiere el conocimiento de la variable a la que se ha asignado la función. Esta es la solución menos que ideal:

var foo = function(callAgain){
    console.log( 'Whassup?' );
    // Less then ideal... we're dependent on a variable reference...
    if (callAgain === true) foo(false);
};

foo(true);

// Console Output:
// Whassup?
// Whassup?

// Assign bar to the original function, and assign foo to another function.
var bar = foo;
foo = function(){
    console.log('Bad.')
};

bar(true);

// Console Output:
// Whassup?
// Bad.

La intención aquí fue que la función anónima se llame a sí misma de forma recursiva, pero cuando cambia el valor de foo, terminas con un error potencialmente difícil de rastrear.

En su lugar, podemos dar a la función anónima una referencia a sí misma al darle un nombre privado, de esta manera:

var foo = function myself(callAgain){
    console.log( 'Whassup?' );
    // Less then ideal... we're dependent on a variable reference...
    if (callAgain === true) myself(false);
};

foo(true);

// Console Output:
// Whassup?
// Whassup?

// Assign bar to the original function, and assign foo to another function.
var bar = foo;
foo = function(){
    console.log('Bad.')
};

bar(true);

// Console Output:
// Whassup?
// Whassup?

Tenga en cuenta que el nombre de la función está restringido a sí mismo. El nombre no se ha filtrado en el ámbito exterior:

myself(false); // ReferenceError: myself is not defined

Esta técnica es especialmente útil cuando se trata de funciones anónimas recursivas como parámetros de devolución de llamada:

5
// Calculate the fibonacci value for each number in an array:
var fib = false,
    result = [1,2,3,4,5,6,7,8].map(
        function fib(n){
            return ( n <= 2 ) ? 1 : fib( n - 1 ) + fib( n - 2 );
        });
// result = [1, 1, 2, 3, 5, 8, 13, 21]
// fib = false (the anonymous function name did not overwrite our fib variable)