【发布时间】:2017-01-04 10:19:05
【问题描述】:
在更多地适应 javascript 中的函数式编程时,我想知道如何最好地(就函数式实践和简单易读的代码而言)解决以下问题。
我有一个返回对象的替代版本的函数。
function doThis(obj) {
return {
...obj,
something: 'Changed'
}
}
不错!一个做一件事的简单函数,可以在各种情况下使用,也可以与其他函数组合使用。
对于一个对象
// Ex 1 - One function
let changed = doThis(original);
// Ex 2 - Many functions
let changed = andMore(doThat(doThis(original)));
// Ex 3 - Many functions, that need additional arguments
let changed = andMore(doThat(doThis(original, 'foo'), 'bar'), 'foo');
// or
let changed = andMore(
doThat(
doThis(original, 'foo'),
'bar'
),
'foo'
);
对象数组
// Ex 4 - One function
let changed = originals.map(doThis);
// Ex 5 - Many functions
let changed = originals
.map(doThis)
.map(doThat)
.map(andMore);
// Ex 6
let changed = originals
.map(original => doThis(original, 'foo'))
.map(changed => doThat(changed, 'bar'))
.map(changed => andMore(changed, 'foo'));
但是,函数(出于某种原因)必须异步执行它的操作,因此它们返回一个 Promise,而不是像以前那样返回预期值。
对于一个对象
// Ex 7 - One function
doThis(original)
.then(changed => {
// continue
});
// Ex 8 - Many functions
doThis(original)
.then(doThat)
.then(andMore)
.then(changed => {
// continue
});
// Ex 9 - Many functions, that need additional arguments
doThis(original, 'foo')
.then(changed => doThat(changed, 'bar'))
.then(changed => andMore(changed, 'foo'))
.then(changed => {
// continue
});
对象数组
// Ex 10 - One function
Promise.all(originals => originals.map(original => doThis(original)))
.then(changed => {
// continue
});
// Ex 11 - Many functions
Promise.all(originals.map(original => doThis(original)))
.then(changed => Promise.all(changed.map(oneChanged => doThat(oneChanged)))
.then(changed => Promise.all(changed.map(oneChanged => andMore(oneChanged)))
.then(changed => {
// continue
});
// Ex 12 - Many functions, that need additional arguments
Promise.all(originals.map(original => doThis(original, 'foo')))
.then(changed => Promise.all(changed.map(oneChanged => doThat(oneChanged, 'bar')))
.then(changed => Promise.all(changed.map(oneChanged => andMore(oneChanged, 'foo')))
.then(changed => {
// continue
});
即使像这样运行一个或三个函数的简化案例,一些示例开始变得非常难看。
我猜这两个主要原因是
- 当需要额外的参数时
- 需要为返回承诺的对象数组包装
Promise.all。
“问题 1”的一个解决方案可能是让函数返回一个函数,以消除在使用主函数的任何地方都需要包装函数。比如:
function doThis(option) {
return function(obj) {
// ...
};
}
// Ex 6 can now be simplified to
someChain
.map(doThis('foo'))
.map(doThat('bar'))
.map(andMore('foo'))
但是那是好的函数式编程吗?或者有没有更好的方法来解决这个问题?
“问题 2”的一个解决方案可能是将函数包装在一个可重用函数中,该函数检查传递的参数是对象还是数组,对于后者,为数组中的每个对象运行回调:
function oneOrMany(callback) {
return (subject) => Array.isArray(subject) ?
subject.map(oneSubject => callback(oneSubject))
:
callback(subject);
}
const doThis = oneOrMany(original => {
return {
...original,
something: 'Changed'
};
});
现在,doThis 既可以用于单个对象(例如在 Ex 8 中),也可以用于对象数组(而不是 Ex 11):
// Ex
doThis(originals)
.then(doThat)
.then(andMore)
.then(changed => {
// continue
});
看起来比 Ex 11 更简单、更易读。但那是好的函数式编程吗?或者有没有更好的方法来解决这个问题?
【问题讨论】:
标签: javascript functional-programming