文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

请停止使用嵌套的 if,改为此方法

2024-11-30 09:22

关注

不要这样做!:

// JavaScript


function sendMoney(account, amount) {
  if (account.balance > amount) {
    if (amount > 0) {
      if (account.sender === 'user-token') {
        account.balance -= amount;
        console.log('Transfer completed');
      } else {
        console.log('Forbidden user');
      }
    } else {
      console.log('Invalid transfer amount');
    }
  } else {
    console.log('Insufficient funds');
  }
}

这里有一个更好的方法:

// JavaScript


function sendMoney(account, amount) {
  if (account.balance < amount) {
    console.log('Insufficient funds');
    return;
  }
  if (amount <= 0) {
    console.log('Invalid transfer amount');
    return;
  }
  if (account.sender !== 'user-token') {
    console.log('Forbidden user');
    return;
  }
  account.balance -= amount;
  console.log('Transfer completed');
}

看看它清洁了多少?我们没有嵌套 if,而是使用多个 if 语句来执行检查,如果条件不满足则立即返回。在这种模式中,我们可以将每个 if 语句称为保护子句。

如果您经常使用 Node.js,您可能在 Express 中间件中看到过以下流程:

// JavaScript


function authMiddleware(req, res, next) {
  const authToken = req.headers.authorization;
  if (!authToken) {
    return res.status(401).json({ error: 'Unauthorized' });
  }
  if (authToken !== 'secret-token') {
    return res.status(401).json({ error: 'Invalid token' });
  }
  if (req.query.admin === 'true') {
    req.isAdmin = true;
  }
  next();
}

这比前面好多了,对吧?:

// JavaScript


function authMiddleware(req, res, next) => {
  const authToken = req.headers.authorization;


  if (authToken) {
    if (authToken === 'secret-token') {
      if (req.query.admin === 'true') {
        req.isAdmin = true;
      }
      return next();
    } else {
      return res.status(401).json({ error: 'Invalid token' });
    }
  } else {
    return res.status(401).json({ error: 'Unauthorized' });
  }
};

你永远不会超出一层嵌套。我们可以避免回调地狱中出现的混乱情况。

如何将嵌套的 if 转换为保护子句

这样做的逻辑很简单:

1.找到最里面的/成功if

这里我们可以清楚地看到它是 cond3 if。在此之后,如果我们不再进行任何检查并采取我们一直想要采取的行动。

// JavaScript


function func(cond1, cond2, cond3) {
  if (cond1) {
    if (cond2) {
      if (cond3) {
        console.log('PASSED!');
        console.log('taking success action...');
      } else {
        console.log('failed condition 3');
      }
    } else {
      console.log('failed condition 2');
    }
  } else {
    console.log('failed condition 1');
  }
}

2.将最外层的if取反并返回

否定 if 条件以将 else 语句的主体放在那里并在后面添加 return。

删除 else 大括号(保留正文,它仍然包含以前嵌套的 if,并将右 if 大括号移到 return 之后。

所以:

// JavaScript


function func(cond1, cond2, cond3) {
  if (!cond1) { // 👈 inverted if condition
    // 👇 body of former else clause 
    console.log('failed condition 1'); 


    return; // 👈 exit on fail
  }


  // 👇 remaining nested ifs to convert to guard clauses
  if (cond2) {
    if (cond3) {
      console.log('PASSED!');
      console.log('taking success action...');
    } else {
      console.log('failed condition 3');
    }
  } else {
    console.log('failed condition 2');
  }
}

3. 对每个嵌套的 if 执行同样的操作,直到成功 if

// JavaScript


function func(cond1, cond2, cond3) {
  if (!cond1) {
    console.log('failed condition 1');
    return;
  }
  if (!cond2) {
    console.log('failed condition 2');
    return;
  }


  // 👇 remaining nested ifs to convert
  if (cond3) {
    console.log('PASSED!');
    console.log('taking success action...');
  } else {
    console.log('failed condition 3');
  }
}

最后:

// JavaScript


function func(cond1, cond2, cond3) {
  if (!cond1) {
    console.log('failed condition 1');
    return;
  }
  if (!cond2) {
    console.log('failed condition 2');
    return;
  }
  if (!cond3) {
    console.log('failed condition 3');
    return;
  }
  console.log('PASSED!');
  console.log('taking success action...');
}

提示:

安装 JavaScript Booster 扩展后,在 VS Code 中反转 if 语句很容易。

在这里,我们只需将光标放在 if 关键字上并激活“显示代码操作”命令(默认情况下为 Ctrl + .)

提示:

将保护子句拆分为多个函数以始终避免 else

如果我们在 if/else 中检查数据后想做其他事情怎么办?例如:

// JavaScript


function func(cond1, cond2) {
  if (cond1) {
    if (cond2) {
      console.log('PASSED!');
      console.log('taking success action...');
    } else {
      console.log('failed condition 2');
    }
    console.log('after cond2 check');
  } else {
    console.log('failed condition 1');
  }
  console.log('after cond1 check');
}

在此函数中,无论 cond1 的值如何,“after cond1 check”行仍将打印。如果 cond1 为 true,则 cond2 值也类似。

在这种情况下,使用保护子句需要做更多的工作:

如果我们尝试使用保护子句,我们最终会重复 if/else 检查之后的行:

function func(cond1, cond2) {
  if (!cond1) {
    console.log('failed condition 1');
    console.log('after cond1 check');
    return;
  }


  if (!cond2) {
    console.log('failed condition 2');
    console.log('after cond2 check');
    console.log('after cond1 check');
    return;
  }
  console.log('PASSED!');
  console.log('taking success action...');
  console.log('after cond2 check');
  console.log('after cond1 check');
}


func(true);

因为必须打印这些行,所以我们在返回之前在保护子句中打印它们。然后,我们在所有(!)以下保护子句中打印它。再次,在主函数体中,如果所有的保护子句都通过了。

那么我们能做些什么呢?我们怎样才能在使用保护子句的同时仍然坚持 DRY 原则呢?

好吧,我们将逻辑拆分为多个函数:

// JavaScript
function func(cond1, cond2) {
  checkCond1(cond1, cond2);
  console.log('after cond1 check');
}


function checkCond1(cond1, cond2) {
  if (!cond1) {
    console.log('failed condition 1');
    return;
  }
  checkCond2(cond2);
  console.log('after cond2 check');
}


function checkCond2(cond2) {
  if (!cond2) {
    console.log('failed condition 2');
    return;
  }
  console.log('PASSED!');
  console.log('taking success action...');
}

让我们将其应用到我们之前看到的 Express 中间件中:

// JavaScript


function authMiddleware(req, res, next) {
  checkAuthValidTokenAdmin(req, res, next);
}


function checkAuthValidTokenAdmin(req, res, next) {
  const authToken = req.headers.authorization;
  if (!authToken) {
    return res.status(401).json({ error: 'Unauthorized' });
  }
  checkValidTokenAdmin(req, res, next);
}
function checkValidTokenAdmin(req, res, next) {
  const authToken = req.headers.authorization;
  if (authToken !== 'secret-token') {
    return res.status(401).json({ error: 'Invalid token' });
  }
  checkAdmin(req, res, next);
}
function checkAdmin(req, res, next) {
  if (req.query.admin === 'true') {
    req.isAdmin = true;
  }
  next();
}

在某种程度上,我们用责任链模式替换了 if/else 语句。

当然,对于像基本 Express 请求中间件这样的简单逻辑来说,这可能有点过分了,但这里的优点是它将每个额外的检查委托给一个单独的函数,分离职责并防止过度嵌套。

总结

在代码中使用嵌套的 if 可能会导致代码复杂且难以维护。相反,我们可以使用保护子句来使我们的代码更具可读性和线性性。我们可以将保护子句应用于不同的场景,并将其拆分为多个功能,以避免重复和职责分割。通过采用这种模式,我们最终会编写出更干净、更易于维护的代码。

来源:web前端开发内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯