【问题标题】:how to avoid nested switch?如何避免嵌套开关?
【发布时间】:2009-03-24 18:22:49
【问题描述】:

我正在使用 JavaScript 为 Web 应用程序创建上下文菜单。菜单可以出现在许多上下文中,并且有不同的选择。对于每个上下文/选择,我可以有不同的功能:

grid1_delete()
grid1_duplicate()
grid2_delete()
grid2_add()
grid2_duplicate()

并在构建菜单时对其进行硬编码。我不喜欢的是可能会有很多重复的代码。所以我在考虑使用调度程序函数,但它可能会导致可能很长的嵌套 switch 语句:

function contextMenuClick(context, menuItem) {
    var action = menuItem.innerHTML;
    switch (context) {
        case 'grid1':
            switch(action) {
                 case('delete'):
                      // do delete for grid1
                      break;
                 case('duplicate'):
                      // do duplicate for grid1
                      break;
                 default:
                      console.log('undefined action in contextMenuClick/grid1: ' + context);
            }
            break;
        case 'grid2':
            switch(action) {
                 case('add'):
                      // do add for grid2
                      break;
                 case('delete'):
                      // do delete for grid2
                      break;
                 case('duplicate'):
                      // do duplicate for grid2
                      break;
                 default:
                      console.log('undefined action in contextMenuClick/grid2: ' + context);
            }
            break;
        default:
            console.log('undefined context in contextMenuClick: ' + context);
        }

哎呀。一定有更好的方法。也许调度员的麻烦多于它的价值。我看过一些 the related posts,但我不太了解如何将它们应用于这种确切的情况。

【问题讨论】:

  • 不同的网格支持不同的功能还是都支持同一套?
  • 我不清楚 grid1_delete 和 grid2_delete 有什么不同。他们对不同的物体做同样的事情吗?还是他们做了根本不同的事情?如果是前者,则应将它们组合成一个通用函数。
  • 不同的网格支持不同的功能。更糟糕的是,同一网格的不同行支持不同的功能,和/或作用于不同类型对象的类似功能。理论上,可能会发生一些重构/参数化,但可能并非在所有情况下都发生。

标签: javascript nested switch-statement


【解决方案1】:

在 Javascript 中很少需要 Switch 语句。一般来说,您可以只使用字典/地图之类的对象并直接进行查找:foo.bar 等价于foo['bar']

另外,对于“全局”变量,some_global_func() 等价于window.some_global_func(),也可以写成var f = 'some_global_func'; window[f]():你永远不需要eval 来根据变量名称动态选择变量或调用函数。不过,一般而言,这样做时,您应该更愿意将函数存储在对象中而不是全局范围内(即在 window 对象中)。

因此,假设 grid1_deletegrid2_delete 根本不同并且不能组合成通用函数,您可以执行以下操作而无需过多更改代码:

var grid_actions = {
    'grid1': {
        'delete': function() { /* ... */ },
        'duplicate': function() { /* ... */ }
    },
    'grid2': {
        'delete': function() { /* ... */ },
        'add': function() { /* ... */ },
        'duplicate': function() { /* ... */ }
    }
}

function contextMenuClick(context, menuItem) {
    var action = menuItem.innerHtml;
    if (context in grid_actions) {
        if (action in grid_actions[context]) {
            grid_actions[context][action]();
        } else {
            console.log('undefined action in contextMenuClick/' + context + ': ' + action);
        }
    } else {
        console.log('undefined context in contextMenuClick: ' + context);
    }
}

不过,更好的解决方案是重构事物,让这些函数成为每个上下文的对象方法,就像 @le dorfier 建议的那样。

【讨论】:

    【解决方案2】:

    如何为“上下文”传递一个实际的对象引用而不仅仅是一个字符串?这样,你就只有一个 switch 语句:

    function contextMenuClick(grid, menuItem) {
        var action = menuItem.innerHTML;
        switch(action) {
           case('delete'):
              grid.delete();
              break;
           case('duplicate'):
              grid.duplicate();
              break;
        }
    }
    

    更好的是,只需将处理程序直接绑定到正确的对象/方法。

    【讨论】:

      【解决方案3】:

      最简单的好简化是让每个开关都包含一个开关。

      如果每个上下文都有一个对象,则可以向每个接受菜单作为参数的对象添加一个函数。

      【讨论】:

        【解决方案4】:

        使用 eval(context + "_" + action + "();") 可能会起作用,但非常危险,因为它会让您的客户端在您的脚本中执行几乎任意的函数。 (任何与 X_Y 匹配的东西)。是的。 eval 主要是邪恶的。

        怎么样

        switch(context+"_"+action) { 
            case ("grid1_add"):  grid1_add(); 
        [...]
        } 
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-10-05
          • 2013-01-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-12-26
          相关资源
          最近更新 更多