首页 > 解决方案 > 函数式编程 if 语句

问题描述

我在 js 中有类似于以下伪代码(数字是占位符):

    if (user.isActive()) {
        if (user.hasManyComments()) {
            if (user.isSpecial()) {
                return {ok: true}
            } else {
                return {ok: false, error: 'has comments'}
            }
        } else { 
             return {ok:true}
        }
    } else {
        return {ok: true}
    }
} else {
    return {ok: false, error: 'err'}
}

如何将代码同时翻译成功能性和可读性?

我更喜欢以 JS 为例。

我知道在 FP 中您没有复杂的 if 语句,但在某些情况下很难删除复杂的 if 语句。

图书馆可供使用。

如果我只有一个级别的 ifs 没问题,但如果级别达到 3,4 级别就很难了

谢谢

标签: functional-programming

解决方案


对于此代码:

    if (user.isActive()) {
        if (user.hasManyComments()) {
            if (user.isSpecial()) {
                return {ok: true}
            } else {
                return {ok: false, error: 'has comments'}
            }
        } else { 
             return {ok:true}
        }
    } else {
        return {ok: true}
    }

我认为它只需要一些重构酱。首先,您有 3 个好的路径 ( return {ok: true}) 和 2 个可能结果的错误路径,但是您有 4 个返回语句。让我们看看我们是否可以将其降低到 1-1 的比例:

    return !user.isActive() || (!user.hasManyComments() || user.isSpecial()) ?
      {ok: true} :
      {ok: false, error: 'has comments'};

经验法则:您应该检查一次条件,并且没有比实际代码路径更多的返回语句。坦率地说,我不一定认为它比你的原版更具可读性,即使更短。请注意,我基本上已经打过它,这里有一定程度的中间。为了使它更具可读性,因为我们使用了很多否定,我们可以做这样的事情:

    const tooManyComments = user.isActive() && 
      user.hasManyComments() &&
      !user.isSpecial();
    
    return tooManyComments ? {ok: false, err: 'err'} : {ok: true};

现在我们只检查错误路径,否则返回 true。

回复评论中的问题

如果你想让它更短,你可以通过滥用逗号操作符。但这可能是一个更清洁(并且仍然简短而简单)的解决方案:

    const hasTooManyComments = user => (user.isActive() && 
      user.hasManyComments() &&
      !user.isSpecial());
    
    const response = hasTooManyComments(user) ? 
      {ok: false, err: 'err'} :
      {ok: true};

你也可以让它成为一个函数:

    const generateResponse = user => hasTooManyComments(user) ? ...

推荐阅读