JavaScript Funciones como variable


Ejemplo

Una declaración de función normal se ve así:

function foo(){
}

Una función definida como esta es accesible desde cualquier lugar dentro de su contexto por su nombre. Pero a veces puede ser útil tratar las referencias de funciones como referencias de objetos. Por ejemplo, puede asignar un objeto a una variable en función de un conjunto de condiciones y luego recuperar una propiedad de uno u otro objeto:

var name = 'Cameron';
var spouse;

if ( name === 'Taylor' ) spouse = { name: 'Jordan' };
else if ( name === 'Cameron' ) spouse = { name: 'Casey' };

var spouseName = spouse.name;

En JavaScript, puedes hacer lo mismo con las funciones:

// Example 1
var hashAlgorithm = 'sha1';
var hash;

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

hash('Fred');

En el ejemplo anterior, el hash es una variable normal. Se le asigna una referencia a una función, después de lo cual la función a la que hace referencia puede invocarse utilizando paréntesis, al igual que una declaración de función normal.

El ejemplo anterior hace referencia a funciones anónimas ... funciones que no tienen su propio nombre. También puede usar variables para referirse a funciones nombradas. El ejemplo anterior podría reescribirse así:

// Example 2
var hashAlgorithm = 'sha1';
var hash;

if ( hashAlgorithm === 'sha1' ) hash = sha1Hash;
else if ( hashAlgorithm === 'md5' ) hash = md5Hash;

hash('Fred');

function md5Hash(value){
    // ...
}

function sha1Hash(value){
    // ...
}

O bien, puede asignar referencias de funciones de las propiedades del objeto:

// Example 3
var hashAlgorithms = {
    sha1: function(value) { /**/ },
    md5: function(value) { /**/ }
};

var hashAlgorithm = 'sha1';
var hash;

if ( hashAlgorithm === 'sha1' ) hash = hashAlgorithms.sha1;
else if ( hashAlgorithm === 'md5' ) hash = hashAlgorithms.md5;

hash('Fred');

Puede asignar la referencia a una función mantenida por una variable a otra omitiendo los paréntesis. Esto puede resultar en un error fácil de cometer: intentar asignar el valor de retorno de una función a otra variable, pero asignar accidentalmente la referencia a la función.

// Example 4
var a = getValue;
var b = a; // b is now a reference to getValue.
var c = b(); // b is invoked, so c now holds the value returned by getValue (41)

function getValue(){
    return 41;
}

Una referencia a una función es como cualquier otro valor. Como ha visto, se puede asignar una referencia a una variable, y el valor de referencia de esa variable se puede asignar posteriormente a otras variables. Puede pasar las referencias a funciones como cualquier otro valor, incluida la transferencia de una referencia a una función como el valor de retorno de otra función. Por ejemplo:

// Example 5
// getHashingFunction returns a function, which is assigned
// to hash for later use:
var hash = getHashingFunction( 'sha1' );
// ...
hash('Fred');


// return the function corresponding to the given algorithmName
function getHashingFunction( algorithmName ){
    // return a reference to an anonymous function
    if (algorithmName === 'sha1') return function(value){ /**/ };
    // return a reference to a declared function
    else if (algorithmName === 'md5') return md5;
}

function md5Hash(value){
    // ...
}

No es necesario asignar una referencia de función a una variable para invocarla. Este ejemplo, aprovechando el ejemplo 5, llamará a getHashingFunction y luego invocará la función devuelta y pasará su valor de retorno a hashedValue.

// Example 6
var hashedValue = getHashingFunction( 'sha1' )( 'Fred' );

Una nota sobre el alzamiento

Tenga en cuenta que, a diferencia de las declaraciones de funciones normales, las variables que hacen referencia a las funciones no están "elevadas". En el ejemplo 2, las funciones md5Hash y sha1Hash se definen en la parte inferior de la secuencia de comandos, pero están disponibles en todas partes inmediatamente. No importa dónde defina una función, el intérprete lo "eleva" al máximo de su alcance, lo que lo hace disponible de inmediato. Este no es el caso de las definiciones de variables, por lo que se romperá un código como el siguiente:

var functionVariable;

hoistedFunction(); // works, because the function is "hoisted" to the top of its scope
functionVariable(); // error: undefined is not a function.

function hoistedFunction(){}
functionVariable = function(){};