4

Web アプリの JavaScript でコンテキスト メニューを作成しています。メニューはさまざまなコンテキストで表示され、さまざまな選択肢があります。コンテキスト/選択ごとに異なる機能を使用できます。

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);
        }

うん。もっと良い方法があるはずです。たぶん、ディスパッチャは価値があるよりも面倒です。関連する投稿 いくつかを見てきましたが、この正確な状況にそれらを適用する方法がよくわかりません。

4

4 に答える 4

7

Javascript で switch ステートメントが必要になることはほとんどありません。一般に、辞書/マップなどのオブジェクトを使用して直接検索を行うことができます:foo.barは と同等foo['bar']です。

また、「グローバル」変数の場合、some_global_func()は と同等でwindow.some_global_func()、次のように書くこともできます。変数を選択したり、その名前に基づいて動的に関数を呼び出したりする必要はありvar f = 'some_global_func'; window[f]()ませんevalただし、一般的には、関数をグローバル スコープ (オブジェクト内) ではなく、オブジェクト内に格納することをお勧めしますwindow

grid1_deleteしたがって、とgrid2_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が示唆するように、これらの関数を各コンテキストのオブジェクトのメソッドにするようにリファクタリングすることです。

于 2009-03-24T19:18:45.463 に答える
2

文字列だけでなく、実際のオブジェクト参照を「コンテキスト」に渡すのはどうですか? そうすれば、switch ステートメントは 1 つだけになります。

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

さらに良いことに、ハンドラーを正しいオブジェクト/メソッドに直接バインドするだけです。

于 2009-03-24T18:47:37.817 に答える
1

最も簡単な単純化は、スイッチを含むすべての機能を各スイッチに持たせることです。

コンテキストごとにオブジェクトがある場合は、メニューを引数として受け入れる関数を各オブジェクトに追加できます。

于 2009-03-24T18:24:44.483 に答える
0

eval(context + "_" + action + "();")の使用に沿った何かが機能する可能性がありますが、クライアントがスクリプト内でほぼ任意の関数を実行できるようになるため、非常に危険です。(X_Yに一致するもの)。はい。evalはほとんど悪です。

どうですか

switch(context+"_"+action) { 
    case ("grid1_add"):  grid1_add(); 
[...]
} 
于 2009-03-24T18:26:54.637 に答える