Funciones sin nombre
En pocas palabras, una lambda es una función sin nombre o una función anónima. Un pequeño fragmento de código ejecutable, que se puede pasar como si fuera una variable. En JavaScript:
function () {}; // very simple
Veamos ahora algunos usos de estas lambdas.
Resumen de código repetitivo
Las lambdas se pueden utilizar para abstraer el código repetitivo. Por ejemplo, bucles. Estamos acostumbrados a escribir for
y while
bucles todo el día. Pero este es un código que no se escribe. Podríamos extraer el código dentro del ciclo, la parte más importante del ciclo, y abstraer el resto:
for (var i=0; i<array.length; i++) {
// do what something useful with array[i]
}
mediante el uso de la forEach
matriz de objetos, se convierte en:
array.forEach(function (element, index) {
// do something useful with element
// element is the equivalent of array[i] from above
});
La abstracción anterior puede no ser tan útil, pero hay otras funciones de orden superior, como forEach
, que realizan tareas mucho más útiles. Por ejemplo filter
:
var numbers = [1, 2, 3, 4];
var even = [];
// keep all even numbers from above array
for (var i=0; i<numbers.length; i++) {
if (numbers[i] % 2 === 0) {
even.push(numbers[i]);
}
}
alert(even);
// Using the filter method
even = [1, 2, 3, 4].filter(function (number) {
return number % 2 === 0;
});
alert(even);
Retraso en la ejecución del código
En algunos entornos, en los que el concepto de evento está disponible, podríamos usar lambdas para responder a eventos que pueden ocurrir en algún momento.
window.onload = function () {
alert("Loaded");
};
window.setTimeout(function () {
alert("Code executed after 2 seconds.");
}, 2000);
Esto podría haberse hecho de otras formas, pero son bastante detalladas. Por ejemplo, en Java existe elRunnable
interfaz.
Fábricas de funciones
Hasta este punto, solo usamos lambdas principalmente por sus capacidades sintácticas de azúcar. Pero hay situaciones en las que las lambdas pueden ser mucho más útiles. Por ejemplo, podemos tener funciones que devuelvan lambdas. Digamos que tenemos una función que queremos que sus valores de retorno se almacenen en caché.
var users = [];
var getUser = function (name) {
if (! users[name]) {
// expensive operations to get a user. Ajax for example
users[name] = user_from_ajax;
}
return users[name];
};
Más adelante, podemos notar que tenemos una función similar:
var photos = [];
var getPhoto = function (name) {
if (! photo[name]) {
// expensive operations to get a user. Ajax for example
photos[name] = photo_from_ajax;
}
return photos[name];
};
Claramente hay un patrón ahí, así que vamos a abstraerlo. El uso de Let memoization .
/**
* @param {Array} store Data structure in which we cache lambda's return values
* @param {Function} lambda
* @return {Function} A function that caches the result of calling the lambda param
*/
var memoize = function (store, lambda) {
// return a new lambda
return function (name) {
if (! store[name]) {
// Execute the lambda and cache the result
store[name] = lambda(name);
}
return store[name];
};
};
var getUsers = memoize([], function (name) {
// expensive operations to get a user. Ajax for example
});
var getPhotos = memoize([], function (name) {
// expensive operations to get a photo. Ajax for example
});
Como puede ver, al usar lambdas, pudimos abstraer la lógica de almacenamiento en caché / memorización. Si para el otro ejemplo hubiera algunas soluciones, creo que este problema en particular difícilmente se resuelve con otras técnicas. Logramos extraer un código repetitivo importante en un solo lugar. Sin mencionar que nos deshicimos del users
yphotos
variables globales .
Al mirar su perfil, veo que es principalmente un usuario de Python. Para el patrón anterior, Python tiene el concepto de decoradores. Hay muchos ejemplos en la red para decoradores de memorias . La única diferencia es que en Python lo más probable es que tenga una función anidada con nombre dentro de esa función decoradora. La razón es que Python solo admite lambdas de expresión única. Pero el concepto es el mismo.
Como ejemplo del uso de Python lambda. El código anterior en el que filtramos números pares se puede representar en Python de esta manera:
filter(lambda x: x % 2 == 0, [1, 2, 3, 4])
De todos modos, las lambdas no son tan poderosas sin cierres. Los cierres es lo que hace que el concepto de lambdas sea tan poderoso. En mi ejemplo de memorización, he utilizado cierres para crear un cierre alrededor del store
parámetro. De esta manera, tengo acceso a ese parámetro incluso después de que la memoize
función haya devuelto su resultado (una lambda).