繁体   English   中英

Javascript - 我有 300 个 if/else 语句。 我应该改用 switch 吗?

[英]Javascript - I have 300 if/else statements. Should I be using switch instead?

我有一个查找路径并重写路径的 js 文件,它有 300 多个 if/else 语句。 我正在寻找清理它的方法,但我还需要确保它对于下一个将要处理它的人来说是可读的。 我的第一个想法是将所有这些 if 语句转换为三元或 switch 语句,但我不确定这是否是最好的方法。 我试图平衡编写“更好”代码的冲动,但我还需要确保它保持可读性,并且当前的 if/else 结构读起来很好。

例子:

if (request.uri.match(^\/path1\/.*$)) {
     request.uri = request.uri.replace(/^\/path1\/(.*)$/) "newPath" + "$1");
} else if (request.uri.match(^\/path2\/.*$)) {
     request.uri = request.uri.replace(/^\/path2\/(.*)$/) "newPath" + "$1");
} else if (request.uri.match(^\/path3\/.*$)) {
     request.uri = request.uri.replace(/^\/path3\/(.*)$/) "newPath" + "$1");
}

我会说 300 个 if 语句中的 75% 看起来相似。 path1、path2 示例过于简单,每个示例的正则表达式从简单到复杂。 除了重写 URL 之外,另外 25% 还包含其他逻辑。 考虑注入标头,或者在某些情况下多一层嵌套的 if/else 语句。

以下是其中一些可能看起来的示例:

else if (request.uri.match(^\/path3(-new)?\/.*$)) {
     request.headers['header'] = {"value": "something"};
     if (request.uri.match(^\/path3\/.*$)) {
          request.uri = request.uri.replace(/^\/path3\/(.*)$/) "/newPathA/" + "$1");
     } else if (request.uri.match(^\/path3-new\/.*$)) {
          request.uri = request.uri.replace(/^\/path3-new\/(.*)$/) "/newPathB/" + "$1");
     }
}

我走上了构建函数来处理不同事情的道路,比如 uri 替换行。 挑战在于函数要替换的代码并不难,而且感觉有点浪费。 我可以有一条线来做到这一点:

request.uri = request.uri.replace(/^\/path3-new\/(.*)$/) "/newPathB/" + "$1");

或者我可以有这个:

function pathModifier(newPath) {
    request.uri = reqUri.replace(/^(\/.*?[\/])(.*)$/, newPath); 
    return;
}

pathRewriter("/newPathA/" + "$1");

我没有存很多钱,这让我把它传递给的人更难阅读。

那么,你会怎么做?

如果你有很多情况,我建议在查找键和它们的值之间使用 HashMap/Object 到 map。

const paths = {
  '/old/path/to/a': '/new/path/to/a',
  '/old/path/to/b': '/new/path/to/b',
  '/old/path/to/c': '/new/path/to/c'
}

function getNewPath(oldPath) {
  return paths[oldPath] || '/fallback/not/found'
}

或者,如果您必须处理不同的业务逻辑,您也可以返回 function

const paths = {
  '/old/path/to/a': () => { return modifyA() },
  '/old/path/to/b': () => { return modifyB() },
  '/old/path/to/c': () => { return modifyC() },
}

function getNewPath(oldPath) {
  return paths[oldPath]()
}

对于大多数情况,我会使用声明性方法,并且仍然公开一种通过传递自定义 function 来扩展它的方法。

这样,您的代码中的重复次数就会减少,同时仍然提供所需的灵活性。

像这样的东西:

const rewrites = {
  '/path1/': ['/newPathA/'],
  '/path2/': ['/newPathB/'],
  '/path3/': ['/newPathC1/', { headers: { name: 'value' } }],
  '/path3-new/': ['/newPathC2/', { headers: { name: 'value' } }],
  '/path4': ['/newPathD', { headers: { name: 'value' }, callback: req => {
    req.customProperty = 123
    req.doCustomStuff()
  } }]
}

function handleRewrites (req, rewrites) {
  const [newPath, options] = Object.keys(rewrites)
    .find(oldPath => req.uri.startsWith(oldPath)) ?? []

  if (newPath) {
    req.uri = newPath + req.uri.slice(oldPath.length)
    if (options?.headers) Object.assign(req.headers, options.headers)
    options?.callback?.(req)
  }
}

当然,您可以自由设计如何声明重写的“领域特定语言”,因为它最适合您的用例。 我选择了一个 object,其中旧路径作为键, [newPath, optionalOptionsObject]作为值,因为大多数时候我希望只有一个oldPath => newPath转换,但它当然可能会有所不同。

如果您在某些情况下需要例如实际的正则表达式,您当然可以更改它并执行类似数组的操作,然后在其中使用[oldPathOrRegex, newPath, optionalOptionsObject]格式的值。 然后,您可以允许简单的字符串路径,但也允许正则表达式(取决于它是instanceof RegExp ,您将应用一种逻辑或另一种逻辑,允许您在声明重写时轻松指定两种类型的路径选择器)。

当然,您仍然需要多次指定多个路由的公共标头。 允许使用与任何每个路由属性合并的公共属性指定(甚至可能是嵌套的)重写组的一种可能方法是创建一个 function,它采用公共设置和另一个重写列表并返回每个的扩展版本给定重写,然后用...传播 function 的结果:

function withOptions (commonOptions, rewrites) {
  for (const rewrite of Object.values(rewrites)) {
    if (!rewrite[1]) rewrite[1] = {}
    const rewriteOptions = rewrite[1]
    
    if (commonOptions.headers || rewriteOptions.headers) {
      rewriteOptions.headers = {
        ...commonOptions.headers,
        ...rewriteOptions.headers
      }
    }
    
    if (commonOptions.callback || rewriteOptions.callback) {
      const childCallback = rewriteOptions.callback
      rewriteOptions.callback = req => {
        commonOptions.callback?.(req)
        childCallback?.(req)
      }
    }
  }
    
  return rewrites
}

const rewrites = {
  '/path1/': ['/newPathA/'],
  '/path2/': ['/newPathB/'],
  ...withOptions({ headers: { name: 'value' } }, {
    '/path3': ['/newPathC2/'],
    '/path3-new': ['/newPathC3/']
  }),
  '/path4': ['/newPathD', { headers: { name: 'value' }, callback: req => {
    req.customProperty = 123
    req.doCustomStuff()
  } }]
}

请注意,在此示例中,我编写了withOptions ,因此它会改变给定的重写,因为这是最简单的方法,并且我认为无论如何它都会传递 object 文字。 如果这不是真的,当然可以将其更改为返回副本。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM