下拉菜单'的更改处理程序工作起来有点奇怪

Dropdown's change handler is working a bit weird

本文关键字:起来 工作 程序 处理 下拉菜单      更新时间:2023-09-26

以下是我所做的:

<html><head><script type="text/javascript"> 
function loaded(){
    var selectElems=document.getElementsByName("select");
    for(i=0;i<selectElems.length;i++){
      var elem=selectElems[i];
      elem.onchange=function(){
          alert(elem.selectedIndex);
       }
     }
} </script></head>
<body onload="loaded()">
<select name="select">
      <option>0</option>
      <option>1</option>
      <option>2</option>
      <option>3</option>
      <option>4</option> </select>
 <select name="select">
      <option>0</option>
      <option>1</option>
      <option>2</option>
      <option>3</option>
      <option>4</option></select>
 <select name="select">
      <option>0</option>
      <option>1</option>
      <option>2</option>
      <option>3</option>
      <option>4</option></select>
</body></html>

我需要用JavaScript获取元素的选定索引。但我对此有意见。这是我的代码:http://jsfiddle.net/aRMpt/139/

问题是elem总是指向最后一个select元素。最简单的解决方案是在处理程序中使用this,而不是elem变量http://jsfiddle.net/mendesjuan/aRMpt/140/

function loaded(){
    var selectElems=document.getElementsByName("select");
    for(i=0;i<selectElems.length;i++){
      var elem=selectElems[i];
      elem.onchange=function(){
          // This points to the select element that was changed
          alert(this.selectedIndex);
       }
     }
}

不过,这并不能真正告诉你你的问题是什么。这是一个变通办法(尽管很好)。代码不起作用的原因是闭包函数onchange使用了闭包中相同的elem。调用onchange时,elem指向最后一个select元素。避免这种情况的一种方法是引入另一个闭包,为onchange处理程序冻结elemhttp://jsfiddle.net/mendesjuan/aRMpt/142/

function loaded(){
    var selectElems=document.getElementsByName("select");
    for(i=0;i<selectElems.length;i++){
      var elem=selectElems[i];
      // Freeze the elem variable by creating a function that passes
      // the elem and creates a separate closure for each handler
      elem.onchange= (function(el) {
          // This is the function that will actually be the handler
          return function(){
             // This points to the select element that was changed
             alert(el.selectedIndex);
          }
     }) (elem) 
}

下面是另一个例子,可以帮助您理解上面的例子是如何工作的。

// This is a function that returns another function
// Its only reason is so that we don't use the shared closure 
// variables from the outer scope, it freezes the el
// variable at the moment its called and so that it's available
// when the handler is called
function createOnChangeHandler(el) {
  return function() {
     alert(el.selectedIndex);
  }
}
function loaded(){
    var selectElems=document.getElementsByName("select");
    for(i=0;i<selectElems.length;i++){
      var elem=selectElems[i];
      // If we just use elem here, its value will be what it was assigned last
      // in the loop. That is because the handler won't be called until
      // this loop has finished. However, by calling another function, 
      // a new scope is created with the value that we're passing into it
      elem.onchange = createOnChangeHandler(elem);
}

这种变量的冻结也可以通过使用Function.bind来完成,但这只适用于较新的浏览器;但是,上面的链接向您展示了如何使它适用于不支持它的浏览器。http://jsfiddle.net/mendesjuan/aRMpt/143/

function loaded(){
    var selectElems=document.getElementsByName("select");
    for(i=0;i<selectElems.length;i++){
      var elem = selectElems[i];
      elem.onchange = (function (el) {
        alert("Select index: " + el.selectedIndex)
      }).bind(null, el);
}