Javascript 如何重写这个多参数函数,最终实现无点风格?

Javascript 如何重写这个多参数函数,最终实现无点风格?,javascript,functional-programming,ramda.js,Javascript,Functional Programming,Ramda.js,我是Ramda和函数式编程的新手,我想知道有人会如何改进下面的代码或将其转换为无点风格 const doc = { passwordRecovery: { requested: true, expiresAt: new Date(Date.now() + 1000).toISOString(), code: 'abc' } } const req = { password: '123', passwordRecovery: { code: 'ab

我是Ramda和函数式编程的新手,我想知道有人会如何改进下面的代码或将其转换为无点风格

const doc = {
  passwordRecovery: {
    requested: true,
    expiresAt: new Date(Date.now() + 1000).toISOString(),
    code: 'abc'
  }
}

const req = {
  password: '123',
  passwordRecovery: {
    code: 'abc'
  }
}

const pathCode = R.path(['passwordRecovery', 'code'])
const isValidCode = R.curry(
    (doc, req) => R.all(
        R.hasPath(['passwordRecovery', 'code'], req),
        R.pathEq(['passwordRecovery', 'requested'], true, doc),
        R.compose(R.complement(R.isNil), pathCode)(doc),
        R.equals(pathCode(req), pathCode(doc)),
        R.pipe(
            R.path(['passwordRecovery', 'expiresAt']),
            Date.parse,
            R.gte(R.__, Date.now()),
        )(doc)
    )
);

isValidCode(doc)(req)
几点建议:

避免混淆 不熟悉咖喱的人经常会说同样的话:当你可以做咖喱的时候,为什么要做咖喱呢?他们是对的。那个例子根本不适合讨好别人

如果您的团队只是想熟悉函数式编程,不要让他们感到不必要的困惑。如果可以一次性提供所有参数,只需执行以下操作:

isValidCode(doc, req); // not isValidCode(doc)(req);
不要为了使用Ramda而使用Ramda 这:
R.equals(路径码(req)、路径码(doc))
与:
pathCode(req)==pathCode(doc)
相同

如果您确实想使用RAMDA,请考虑:

无点不是唯一的方法 这当然是一种编写函数的有趣方式,但不能成为目标。假设您需要检查
a
是否等于
'foo'
b
是否等于
'bar'

这是一个无点函数:

const fn = useWith(and, [equals('foo'), equals('bar')]);
再好不过了:

const fn = (a, b) => a === 'foo' && b === 'bar';
?

all
是否正确调用? 根据文档,获取一个函数和一个列表:

all(x => x === 42)([41, 42, 43]);
除非我弄错了,否则您所做的就是调用
all
,并得到每个函数调用的结果。e、 g

all(true, false, true, ...);
避免使用占位符
gte(uuu,Date.now())
可以更改为
flip(gte)(Date.now())

始终如一 在一种情况下,您允许将路径设置为
未定义

// true even for `{passwordRecovery: {code: undefined}}`
hasPath(['passwordRecovery', 'code'], req);
而在另一种情况下,您不会:

compose(R.complement(R.isNil), pathCode)(doc)
保持一致将允许:

const notNil = complement(isNil);
both(pathSatisfies(notNil, pathCode), req, doc)

贝基和指挥官的得分都很好

我主要想问你为什么要用拉姆达来做这个。Ramda有很多好处,但它只能在改进代码时使用。在这里,我认为有一个更简洁的选项,使用了非结构化和默认参数:

const isValidCode=(
{passwordRecovery:{code,requested,expiresAt}={}},//doc
{passwordRecovery:{code:reqCode}={}}//req
)=>请求代码!=无效的
&&代码!=无效的
&&reqCode==代码
&&请求!=无效的
&&expiresAt>=新日期(Date.now()).toISOString()
const doc1={passwordRecovery:{requested:true,expiresAt:new Date(Date.now()+1000).toISOString(),代码:'abc'}
const req1={password:'123',passwordRecovery:{code:'abc'}
const doc2={passwordRecovery:{expiresAt:new Date(Date.now()+1000).toISOString(),代码:'abc'}
const req2={password:'123',passwordRecovery:{code:'abcd'}
控制台日志(
isValidCode(doc1,req1),//true
isValidCode(doc1,req2),//错误
isValidCode(doc2,req1)//错误

)
一个人可以通过尝试不去做来改善它
doc
req
都被多次使用,因此最好有名称来引用它们。虽然我大体上同意这一点,但我对占位符vs
flip
的感觉很复杂。如果OP将重用由
isValidCode(doc)
生成的函数进行多次调用,则currying可能是合法的。当然,即使在那时,除非有必要将其称为“双向”,否则手动咖喱会胜过
R.curry
。我似乎还记得关于不使用占位符的讨论。所以我建议你习惯没有它的工作。我只是想说,如果你能一下子把所有的论点都讲出来,那么“一个接一个”地提供这些论点没有多大意义。不过,这个功能仍然应该是咖喱式的。曾经有过这样的讨论,但这通常是与切换到纯咖喱式而不是拉姆达相当神奇的版本的讨论联系在一起的。至于讨价还价,我只会在有理由逐一提供论据的情况下才讨价还价。我会手动操作,除非出于某种原因我真的需要这两种样式。这在库代码中比在像这样的应用程序代码中更可能。curry是关于部分应用程序的,它推迟了对实际函数体的求值。您不能用语句来实现这一点,也不能像数据一样传递语句。因此,每当您需要这些属性时,您可能需要使用咖喱形式。@bob只是想澄清一下:我所说的是,对于包含两个参数的咖喱函数,例如
add
,如果您手头已经有了这两个数字,那么用
add(1)(2)
代替
add(1,2)
几乎没有什么价值。这是一个让初学者感到困惑的例子。咖喱的一个更好的例子是
[1,2,3].map(add(1))
附录。我刚刚注意到这是多余的:
reqCode!=空和空代码!=null&&reqCode==code
。您可以删除其中一个空检查。为什么要编写
新日期(Date.now())
?这和新日期()的比较不一样吗?同样,如果你在比较日期,那么你应该比较它们的
.getTime()
值,而不是比较它们的
.toISOString()
值。@AaditMShah:这是从原始日期复制的。没有理由这样做。至于
.getTime()
.toISOString()
,我还不太清楚。ISO格式的一个好处是它被设计成可排序的。因此,两者都应该有效。它可以归结为解析字符串格式并将其时间戳与
Date.now()
进行比较,或者格式化
new Date()
与现有的ISO字符串进行比较。在没有测试的情况下,我希望格式化比解析更有效,而且我看不到选择其他格式的重要原因。我遗漏了什么吗?还有,谢谢你指出你刚刚从OP复制了代码。我遗漏了。
const notNil = complement(isNil);
both(pathSatisfies(notNil, pathCode), req, doc)