首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >以可读的方式模拟javascript中的管道操作符

以可读的方式模拟javascript中的管道操作符
EN

Code Review用户
提问于 2019-08-12 11:48:52
回答 1查看 80关注 0票数 2

这篇文章中,我发现了这个看起来非常优雅的Elixir代码:

代码语言:javascript
复制
conn
|> put_session(:current_user, user)
|> put_resp_header(location, "/")
|> put_resp_content_type("text/html")
|> send_resp(302, "You are being redirected")

它使用每个函数的输出作为下一个函数的第一个参数。给定的args被绑定到第二个参数和向上。

我知道关于管道操作员的两种不同的建议正在考虑将来的版本,但是<#>I想知道是否有一种方法可以用今天的Javascript来写一些视觉上和功能上类似的东西?

我想我可以用某种意义上的赛跑,约束除了第一个论点以外的一切?

作为参考,以下是本文中的原始函数定义。他们都返回一个conn

  • assign(conn, key, value)
  • clear_session(conn)
  • put_resp_content_type(conn, content_type, charset)
  • put_resp_header(conn, key, value)
  • put_session(conn, key, value)
  • send_resp(conn, status, body)

我试着提出了一些建议,但我想要输入如何改进这一点/更易读/看起来更好的普通程序员来修改我的代码。

使用ES5.1的基本尝试如下所示:

代码语言:javascript
复制
const {bind, flow} = require('lodash');
const _ = bind.placeholder;

flow(
  bind(put_session, null, _, current_user, user),
  bind(put_resp_header, null, _, location, '/'),
  bind(put_resp_content_type, null, _, 'text/html'),
  bind(send_resp, null, _, 302, 'You are being redirected')
)(conn);

与原作相比,它有点冗长,所以我试着把它压缩一些:

代码语言:javascript
复制
// bind all but first argument - what should I call this?
// bindAllButFirstArgument is a tad bit long
const $ = (...args) => bind(args[0], null, _, args.slice(1));

flow(
  (put_session, current_user, user),
  #qcStackCode#(put_resp_header, location, '/'),
  (put_resp_content_type, 'text/html'),
  #qcStackCode#(send_resp, 302, 'You are being redirected')
)(conn);

这看起来要好一些(除了神秘的$ : ),只要做一些小小的修改,我就可以尝试在语法上突出这个函数,比如

代码语言:javascript
复制
  $(put_session, current_user, user),

看起来像

代码语言:javascript
复制
  pipe.prepare(put_session)(current_user, user),

其中pipe相当于flowpipe.prepare,这是一个为上面提到的管道流“准备”函数的实用函数。好些了吗?你觉得这个怎么样?太浓了?需要多读JSDocs吗?不同的方式?

会像这样

代码语言:javascript
复制
const pipe = (...args) => flow(...args);
pipe.prepare = fn => (...args) => bind(fn, null, _, args);

pipe(
  pipe.prepare(put_session)(current_user, user),
  pipe.prepare(put_resp_header)(location, '/'),
  pipe.prepare(put_resp_content_type)('text/html'),
  pipe.prepare(send_resp)(302, 'You are being redirected')
)(conn);

可运行的示例:https://runkit.com/fatso83/piping-with-binding

EN

回答 1

Code Review用户

发布于 2019-08-15 15:49:02

它使用每个函数的输出作为下一个函数的第一个参数。给定的args被绑定到第二个参数和向上。

只要按照这个描述运行,就可以轻松地创建一个带有2个助手函数的管道操作:

代码语言:javascript
复制
const bind = (fn, ...boundArgs) => callArg => fn(callArg, ...boundArgs)
const pipe = (...fns) => initialArg => fns.reduce((r, fn) => fn(r), initialArg)

pipe(
  bind(put_session, current_user, user),
  bind(put_resp_header, location, '/'),
  bind(put_resp_content_type, 'text/html'),
  bind(send_resp, 302, 'You are being redirected')
)(conn)

bind接受一个函数和绑定参数,并返回一个接受单个参数的函数。当这个返回的函数被调用时,它首先用调用参数调用绑定函数,然后是绑定参数的其余部分。

pipe接受绑定函数的列表,并逐个调用它们。第一个函数获得调用参数,而其余函数获得以前调用的函数的返回值。

这种方法有效地复制了提交人的签名,但不需要提交。它也不处理this。第二个例子很简洁,而第三个例子则不那么臃肿。

票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/225971

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档