在 Javascript 中嵌套许多函数调用(Unix 管道)的好方法
Nice way to nest many function calls (Unix piping) in Javascript
我一直在寻找一种很好地进行嵌套函数调用的方法,以避免出现类似的情况:
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,你们都在回答中添加了独特、有用和有趣的信息。
没有辅助函数
我最初接受你的问题是在 没有 任何辅助函数的情况下执行此操作,但你随后的评论表明情况并非如此。如果辅助函数在范围内,请跳过。
无需添加任何辅助函数,即可使用 ES6 promises:
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); });
I know pipe is a thing in fs libraries, so the function name isn't exactly great. Aside from that, is there anything glaringly wrong with this?
如果你想在这里抛出一个辅助函数,根本不需要 eval
。对于非 promise 化的函数,只需执行:
function pipe(first, ...more) {
return more.reduce((r, f) => f(r), first());
}
和
let result = pipe(function3, function2, function1);
如果您想使用 promise 化函数或混合函数来执行此操作,则:
function pipe(...functions) {
return functions.reduce((p, f) => p.then(f), Promise.resolve());
}
然后你就可以像你展示的那样称呼它了:
pipe(function3, function2, function1, result => {
// ...
});
...但这样做会忽略错误。由于 pipe
return 是最后一个承诺,您可以使用所有承诺的好处
pipe(function3, function2, function1, result => {
// ...
}).catch(failure => {
// ...
});
或
pipe(function3, function2, function1)
.then(result => {
// ...
})
.catch(failure => {
// ...
});
这是一个混合简单函数和 return 承诺的函数的完整示例: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
您只是在编写函数。使用许多库中提供的 compose
函数,或者编写您自己的函数,并将其用作:
compose(function1, function2, function3) ()
换句话说,您的 "pipe" 运算符可以被认为是一个 "comma",用于在调用 compose 时分隔参数。
这是一个真正简单的撰写:
function compose(...fns) {
var lastFunc = fns.pop();
return function() {
return fns.reduceRight(result, fn) {
return fn(result);
}, lastFunc(...arguments));
};
}
你要找的是一个 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 that could bring some pipelining sugar to the language. It's not settled yet它到底是什么样子:
method3()::method2()::method1()
method3()->method2()->method1()
function3()->function2()->function1()
我一直在寻找一种很好地进行嵌套函数调用的方法,以避免出现类似的情况:
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,你们都在回答中添加了独特、有用和有趣的信息。
没有辅助函数
我最初接受你的问题是在 没有 任何辅助函数的情况下执行此操作,但你随后的评论表明情况并非如此。如果辅助函数在范围内,请跳过。
无需添加任何辅助函数,即可使用 ES6 promises:
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); });
I know pipe is a thing in fs libraries, so the function name isn't exactly great. Aside from that, is there anything glaringly wrong with this?
如果你想在这里抛出一个辅助函数,根本不需要 eval
。对于非 promise 化的函数,只需执行:
function pipe(first, ...more) {
return more.reduce((r, f) => f(r), first());
}
和
let result = pipe(function3, function2, function1);
如果您想使用 promise 化函数或混合函数来执行此操作,则:
function pipe(...functions) {
return functions.reduce((p, f) => p.then(f), Promise.resolve());
}
然后你就可以像你展示的那样称呼它了:
pipe(function3, function2, function1, result => {
// ...
});
...但这样做会忽略错误。由于 pipe
return 是最后一个承诺,您可以使用所有承诺的好处
pipe(function3, function2, function1, result => {
// ...
}).catch(failure => {
// ...
});
或
pipe(function3, function2, function1)
.then(result => {
// ...
})
.catch(failure => {
// ...
});
这是一个混合简单函数和 return 承诺的函数的完整示例: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
您只是在编写函数。使用许多库中提供的 compose
函数,或者编写您自己的函数,并将其用作:
compose(function1, function2, function3) ()
换句话说,您的 "pipe" 运算符可以被认为是一个 "comma",用于在调用 compose 时分隔参数。
这是一个真正简单的撰写:
function compose(...fns) {
var lastFunc = fns.pop();
return function() {
return fns.reduceRight(result, fn) {
return fn(result);
}, lastFunc(...arguments));
};
}
你要找的是一个 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 that could bring some pipelining sugar to the language. It's not settled yet它到底是什么样子:
method3()::method2()::method1()
method3()->method2()->method1()
function3()->function2()->function1()