在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
中包含返回promises的对象数组。“问题1”的一个解决方案可能是使函数返回一个函数,以消除在使用main函数的地方对包装函数的需要。类似的东西:
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更简单,更易读。但这是一个很好的函数式编程吗?或者有更好的方法来解决这个问题吗?
答案 0 :(得分:2)
其他参数的一个解决方案可能是制作函数 返回一个函数,以消除对包装函数的需要 到处使用主要功能。
但这是一个很好的功能编程吗?或者,还有更好的方法 解决这个问题?
这很好。它被称为currying。
您也可以通过编程方式执行此操作,而不是重写所有多参数函数,或者在调用位置显式执行部分应用程序,但这主要是语法差异。
Promise.all
的一个解决方案 - 包装返回的对象数组 promises可以将函数包装在一个可重用的函数中 检查传递的参数是一个对象,一个数组和 后者,为数组中的每个对象运行回调。它可以使用 单个对象和对象数组,看起来很多 更简单,更易读 但这是一个很好的函数式编程吗?
不,一点也不。 FP是关于类型的特定,而不是根据传递的内容编写执行不同操作的开放函数。明确地这样做:
function manyParallel(callback) {
return function(subject) {
return Promise.all(subject.map(callback));
};
}
manyParallel(doThis)(originals)
.then(manyParallel(doThat))
.then(manyParallel(andMore))
.then(manyParallel(changed => {
// continue
}));
// or alternatively (but different):
manyParallel(original => original
.then(doThis)
.then(doThat)
.then(andMore)
)(originals)
.then(manyParallel(changed => … ));