Skip to main content

JavaScript 函数组合

一、什么是函数组合

函数组合 compose() 可以把指定的函数串联起来执行,一个函数的输出结果是另一个函数的输入参数,像多米诺骨牌一样依次执行输出最终结果。

类似数学中的复合函数。函数 fg 的组合可以被定义为 f(g(x)),从内到外依次求值。举个例子:

实现输入 Tim, Cook,打印出 HELLO,TIM COOK,用函数组合的方式,对两个函数 greeting(), toUpperCase() 进行组合:

const greeting = (x, y) => {
return `HELLO, ${x} ${y}`;
}

const toUpperCase = (x) => {
return x.toUpperCase();
}

const fn = compose(toUpperCase, greeting);
console.log(fn('Tim', 'Cook')); // HELLO, TIM COOK

上面初始函数 greeting() 的执行结果作为参数传递给 toUpper(),再执行得到最后结果。函数组合的好处在于可专注编写基本函数,将多个单一功能的纯函数进行组合。

二、函数组合的实现

函数组合 compose() 要满足能传入多个基本函数,underscore 的实现如下:

const greeting = (x, y) => {
return `HELLO, ${x} ${y}`;
}

const toUpperCase = (x) => {
return x.toUpperCase();
}

function compose() {
const args = arguments;
// 倒序调用
const start = args.length - 1;
return function () {
let i = start;
let result = args[start].apply(this, arguments);
while (i--) result = args[i].call(this, result);
return result;
};
};

const fn = compose(toUpperCase, greeting);
console.log(fn('Tim', 'Cook')); // HELLO, TIM COOK

三、函数组合的应用

假设要从服务器获取以下数据:

const data = {
result: "SUCCESS",
tasks: [
{
id: 104, complete: false, priority: "high",
dueDate: "2013-11-29", username: "Scott",
title: "Do something", created: "9/22/2013"
},
{
id: 105, complete: false, priority: "medium",
dueDate: "2013-11-22", username: "Lena",
title: "Do something else", created: "9/22/2013"
},
{
id: 107, complete: true, priority: "high",
dueDate: "2013-11-22", username: "Mike",
title: "Fix the foo", created: "9/22/2013"
},
{
id: 108, complete: false, priority: "low",
dueDate: "2013-11-15", username: "Punam",
title: "Adjust the bar", created: "9/25/2013"
},
{
id: 110, complete: false, priority: "medium",
dueDate: "2013-11-15", username: "Scott",
title: "Rename everything", created: "10/2/2013"
},
{
id: 112, complete: true, priority: "high",
dueDate: "2013-11-27", username: "Lena",
title: "Alter all quuxes", created: "10/5/2013"
}
]
};

需要写一个名为 getIncompleteTaskSummaries 的函数,接收一个 username 作为参数,从服务器获取数据,然后筛选出这个用户的未完成的任务的 idsprioritiestitles、和 dueDate 数据,并按照日期升序排序。以 Scott 为例,最终筛选出的数据为:

[
{
id: 110, title: "Rename everything",
dueDate: "2013-11-15", priority: "medium"
},
{
id: 104, title: "Do something",
dueDate: "2013-11-29", priority: "high"
}
]

实现如下:

// 过程式编程
const fetchData = function () {
// 模拟
return Promise.resolve(data)
};

const getIncompleteTaskSummaries = function (membername) {
return fetchData()
.then(function (data) {
return data.tasks;
})
.then(function (tasks) {
return tasks.filter(function (task) {
return task.username == membername
})
})
.then(function (tasks) {
return tasks.filter(function (task) {
return !task.complete
})
})
.then(function (tasks) {
return tasks.map(function (task) {
return {
id: task.id,
dueDate: task.dueDate,
title: task.title,
priority: task.priority
}
})
})
.then(function (tasks) {
return tasks.sort(function (first, second) {
const a = first.dueDate,
b = second.dueDate;
return a < b ? -1 : a > b ? 1 : 0;
});
})
.then(function (task) {
console.log(task)
})
};

getIncompleteTaskSummaries('Scott')