调用在对象中设置的匿名函数,而不是获得预期的结果

时间:2016-04-20 17:51:44

标签: javascript jquery twitter-bootstrap

我正在尝试编写一个有点通用的模态对话框处理函数,因此我可以将控件传递给它来处理不同的操作。这听起来很简单,我认为它会。我正在尝试在一个对象中传递按钮处理函数,该对象循环通过ID将每个函数注册到按钮单击处理程序。它有效,但不是我期望的方式。这是代码(需要bootstrap 3):

function confirmation(question){
    var modalTitle = 'Confirmation';
    var modalContents = question;
    var modalControls = '<button type="button" class="btn btn-primary" id="confirmYes">Confirm</button> <button type="button" class="btn btn-default" id="confirmNo">Cancel</button>';

    var modalButtons = {
        confirmNo: function(){
            console.log('really, no!');
        },
        confirmYes: function(){
            console.log('really, yes!');
        }
    }

    standardModal(modalTitle,modalContents,modalControls,modalButtons);
}

function standardModal(modalTitle,modalContents,modalControls,modalButtons){
    $('#standardModalTitle').html(modalTitle);
    $('#standardModalBody').html(modalContents);
    $('#standardModalControls').html(modalControls);

    for (var prop in modalButtons){
        if(!modalButtons.hasOwnProperty(prop)) continue;

        $('#'+prop).click(function(e){
            e.preventDefault();
            modalButtons[prop]();
        });
    }

    $('#standardModal').modal('show');
}

这是HTML:

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
<div class='modal fade' tabindex='-1' role='dialog' id='standardModal'>
  <div class='modal-dialog'>
    <div class='modal-content'>
      <div class='modal-header'>
        <button type='button' class='close' data-dismiss='modal' aria-label='Close'><span aria-hidden='true'>&times;</span></button>
        <h4 class='modal-title' id='standardModalTitle'></h4>
      </div>
      <div class='modal-body' id='standardModalBody'>

      </div>
      <div class='modal-footer' id='standardModalControls'>
        <button type='button' class='btn btn-default' data-dismiss='modal'>Close</button>
      </div>
    </div>
  </div>
</div>

当我运行确认时('这是一个问题?');我应该在对话框中有两个按钮,确认和取消。我希望Confirm运行modalButtons.confirmYes函数,而Cancel应该运行modalButtons.confirmNo。实际发生的是,两个按钮都调用了modalButtons中定义的最后一个函数。如果confirmYes是最后定义的函数,则它将针对两个按钮运行。

当我在那里抛出console.log语句时,变量输出是我每次都期望的...但是实际的函数调用是错误的。

我做错了什么?

1 个答案:

答案 0 :(得分:1)

当您点击按钮并调用modalButtons[prop]()时,prop评估的内容是什么?记住javascript如何查找变量名称:

  1. 如果变量是在本地定义的,请使用该值
  2. 否则,一次输出1个范围,直到我们到达全局(窗口)范围,并查看是否定义了具有给定名称的变量
  3. 否则,请转到undefined
  4. 在我们的情况下,您点击该按钮,然后执行click回调,javascript会尝试查找prop的值:

    1. prop未在回调范围内定义,因此它会查看下一个外部范围
    2. prop在回调的直接父范围内定义! prop的价值是什么?好吧,它是你循环的最后一个值(数组的最后一个元素)。
    3. 您要做的是定义一个始终指向prop的预期值的变量。最简单的方法是用函数迭代器替换for循环:

      Object.keys(modalButtons).forEach(function (prop) {
         // same loop code as before
      })
      

      不同之处在于,我们在父作用域中声明了一个名为prop的新变量,而不是声明prop一次并在循环的每个卷上更改其值。这是一个微妙的错误,但是你经常遇到的事情,所以了解它是如何工作的很重要。

      这有帮助吗?

      或者查看我对此similar question的回答,如果有帮助,请告诉我!