在 select 元素上分派,无需评估或复制粘贴

Dispatch on select element without eval or copy & paste

编辑:此问题与 "how do I call a javascript function when all I have is a string containing its name" 重复。 dom 互动让人分心。

我想在用户从 html select 元素中选择一个选项时调用 N 个不同的 javascript 函数之一。我想在不重复自己或退回到 eval() 的情况下执行此操作。

修改一个存储在选项值字段中的字符串,然后将它们用作字典中的索引。

<body>
<select onchange="dispatch(this)">
<option value="first_function_name">One</option>
<option value="second_function_name">Two</option>
</select>
</body>

<script>
function first_function() {console.log("There can be only one");}
function second_function() {console.log("Except when there are two");}
function dispatch(selection) {
  var name = selection.value;
  var lookup_table = {
    first_function_name: first_function,
    second_function_name: second_function
  };
  (lookup_table[name])();
}
</script>

修订版 2 将函数存储在值字段中并对其调用 eval。 Eval 给我的印象是笨手笨脚的。

<body>
<select onchange="dispatch(this)"> <!-- Not sure passing this is always OK -->
<option value="first_function()">One</option>
<option value="second_function()">Two</option>
</select>
</body>

<script>
function first_function() {console.log("There can be only one");}
function second_function() {console.log("Except when there are two");}
function dispatch(selection) {eval(selection.value);} /* yuck */
</script>

选项三是针对问题使用代码生成器,但这似乎是失败主义者。什么是明智的、惯用的解决方案?

这是一个小例子(可能需要针对不同的浏览器进行调整):

<select id="mySelect"></select>
<script type="text/javascript">
    (function() {

        var select = document.getElementById("mySelect");
        var options = [ { name: 'One', value:'one', callback: function() {console.log("There can be only one");}},
                        { name: 'Two', value:'two', callback: function() {console.log("Except when there are two");}}];
        options.forEach(
                    function(opt) {
                        var option = document.createElement("option");
                        option.text = opt.name;
                        option.value = opt.value;
                        select.add(option);
                    });
        function onChange() {
            options.some(function(option) {
                if (option.value===select.value) {
                    option.callback();
                    return true;
                }
            });
        }
        select.addEventListener("change", onChange);
    })();
</script>

var closureObject = (function(){    // created scope
    /* so now "this" becomes the closureObject and which has all functions as property and
       can directly refer them by syntax Instance['propertyName'] */
    var closureObject = {};
    closureObject.first_function = function() {
          alert("There can be only one");
    }
    closureObject.second_function = function(){
          alert("Except when there are two");
    }
    return closureObject;
    })();

function dispatch(selection) {
          closureObject[selection](); // ClosureObject could be Global or scoped variable
}
<select onchange="dispatch(this.value)">
<option value="first_function">One</option>
<option value="second_function">Two</option>
</select>