我正在寻找一种很好地进行嵌套函数调用的方法,以避免类似:
var result = function1(function2(function3()));
或类似的东西:
var result = function3();
result = function2(result);
result = function1(result);
像Unix这样的管道就好了:
var result = function3() | function2() | function1();
来源:https://www.npmjs.com/package/babel-plugin-operator-overload
当然|
是按位或操作,这个例子是抽象的。
有没有人知道如何使用ES5,ES6或ES7实现这样的效果而不进行转换?
谢谢T.J Crowder,torazaburo和Bergi,你们在答案中都添加了独特,有用和有趣的信息。
答案 0 :(得分:4)
我最初提出的问题是在没有任何帮助函数的情况下执行此操作,但您后续的评论表明情况并非如此。如果辅助函数在范围内,则省略。
不添加任何帮助函数,您可以使用ES6承诺:
Promise.resolve()
.then(function3)
.then(function2)
.then(function1)
.then(result => {
console.log("result is " + result);
});
它不比
漂亮var result = function1(function2(function3()));
...但至少被调用的函数按照它们被调用的顺序列出,并且promises在多种方面非常灵活。
function function1(arg) {
console.log("function1 called with " + arg);
return "result1";
}
function function2(arg) {
console.log("function2 called with " + arg);
return "result2";
}
function function3() {
console.log("function3 called");
return "result3";
}
Promise.resolve()
.then(function3)
.then(function2)
.then(function1)
.then(result => {
console.log("result is " + result);
});
输出:
function3 called function2 called with result3 function1 called with result2 result is result1
重新评论:
function pipe(){ var str = 'Promise.resolve()'; for(var i = 0; i < arguments.length; i++){ str += '.then(arguments[' + i + '])' } eval(str); } pipe(c, b, a, result => { console.log("result is " + result); });
我知道管道是fs库中的东西,所以函数名称并不是很好。除此之外,这有什么明显的错误吗?
如果你想在此处抛出辅助函数,那么eval
根本不需要。对于非承诺函数,只需执行:
function pipe(first, ...more) {
return more.reduce((r, f) => f(r), first());
}
和
let result = pipe(function3, function2, function1);
如果你想使用promise-ified函数或混合函数,那么:
function pipe(...functions) {
return functions.reduce((p, f) => p.then(f), Promise.resolve());
}
然后你可以按照你展示的方式来调用它:
pipe(function3, function2, function1, result => {
// ...
});
...但这样做会忽略错误。由于pipe
返回最后一个承诺,您可以使用所有承诺善意
pipe(function3, function2, function1, result => {
// ...
}).catch(failure => {
// ...
});
或
pipe(function3, function2, function1)
.then(result => {
// ...
})
.catch(failure => {
// ...
});
这是一个完整的示例,它混合了返回promise的简单函数和函数:Live copy on Babel's REPL
function pipe(...functions) {
return functions.reduce((p, f) => p.then(f), Promise.resolve());
}
function function1(arg) {
console.log("function1 called with " + arg);
return "result1";
}
function function2(arg) {
console.log("function2 called with " + arg);
return new Promise(resolve => {
setTimeout(() => {
resolve("result2");
}, 100);
});
}
function function3() {
console.log("function3 called");
return "result3";
}
pipe(function3, function2, function1)
.then(result => {
console.log("Final result is " + result);
})
.catch(failure => {
console.log("Failed with " + failure);
});
输出:
function3 called function2 called with result3 function1 called with result2 Final result is result1
答案 1 :(得分:4)
你只是在编写功能。使用许多库中提供的compose
函数,或编写自己的函数,并将其用作:
compose(function1, function2, function3) ()
换句话说,你的“管道”操作符可以被认为是一个“逗号”,用于分隔调用中的参数。
这是一个真正简单的作品:
function compose(...fns) {
var lastFunc = fns.pop();
return function() {
return fns.reduceRight(result, fn) {
return fn(result);
}, lastFunc(...arguments));
};
}
答案 2 :(得分:1)
您正在寻找的是pipe
功能,基本上是众所周知的compose
翻转:
var result = pipe(function3, function2, function1)();
它不是内置的(并且没有计划用于任何即将推出的ES修订版),但在Ramda等许多库中都可用;你可以自己轻松地实现它:
function pipe(g, ...fs) {
if (!arguments.length) return x => x;
if (!fs.length) return g;
const f = pipe(...fs);
return x => f(g(x));
}
如果您正在寻找新的语法,那么an ES7 proposal可能会为语言带来一些流水线糖。这是not settled yet究竟是什么样子:
method3()::method2()::method1()
method3()->method2()->method1()
function3()->function2()->function1()