没有名字的函数
简单地说,lambda 是一个没有名字的函数,或者是一个匿名函数。一小段可执行代码,可以像变量一样传递。在 JavaScript 中:
function () {}; // very simple
现在让我们看看这些 lambda 的一些用途。
抽象样板代码
Lambda 可用于抽象出样板代码。例如循环。我们习惯于整天编写for 和while 循环。但这是不写的代码。我们可以提取循环内的代码,这是循环中最重要的部分,并抽象出其余部分:
for (var i=0; i<array.length; i++) {
// do what something useful with array[i]
}
通过使用数组对象的forEach,变为:
array.forEach(function (element, index) {
// do something useful with element
// element is the equivalent of array[i] from above
});
上面的抽象可能没有那么有用,但是还有其他更高阶的函数,比如forEach,可以执行更有用的任务。例如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);
代码执行延迟
在某些可以使用事件概念的环境中,我们可以使用 lambdas 来响应可能在某个时间点发生的事件。
window.onload = function () {
alert("Loaded");
};
window.setTimeout(function () {
alert("Code executed after 2 seconds.");
}, 2000);
这可以通过其他方式完成,但这些方式相当冗长。例如,在 Java 中有 Runnable 接口。
函数工厂
到目前为止,我们主要使用 lambdas 来实现其语法糖功能。但在某些情况下,lambda 可能更有用。例如,我们可能有返回 lambdas 的函数。假设我们有一个函数,我们希望缓存它的返回值。
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];
};
稍后,我们可能会注意到我们有类似的功能:
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];
};
其中显然有一个模式,所以让我们将其抽象出来。让我们使用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
});
如您所见,通过使用 lambda,我们能够抽象出缓存/记忆逻辑。如果对于另一个示例有一些解决方法,我相信使用其他技术很难解决这个特定问题。我们设法将一些重要的样板代码提取到一个地方。更不用说我们去掉了users 和photos 全局变量。
查看您的个人资料,我发现您主要是 Python 用户。对于上述模式,Python 有装饰器的概念。有很多 example on the net for memoization 装饰器。唯一的区别是,在 Python 中,您很可能在装饰器函数中有一个 named 嵌套函数。原因是 Python 只支持单表达式 lambda。但概念是一样的。
作为 Python lambda 使用的示例。上面我们过滤偶数的代码在 Python 中可以这样表示:
filter(lambda x: x % 2 == 0, [1, 2, 3, 4])
无论如何,如果没有闭包,lambda 就不会那么强大。闭包是 lambda 概念如此强大的原因。在我的记忆示例中,我使用闭包围绕store 参数创建闭包。这样,即使memoize 函数返回了它的结果(一个 lambda),我也可以访问该参数。