JavaScript 作用域和闭包语法

JavaScript Scoping and Closure Syntax

我在 JavaScript 代码段中遇到范围界定和关闭问题。我正在尝试更新按钮的 classonclick 属性。基本上这应该在 "High" 和 "Low" 之间切换。我可以在不尝试重新调整参数范围的情况下执行函数,但它没有成功更新属性。因此,我尝试将其重新定义为下面的代码,但现在收到 channel 未定义的错误。谁能帮我解决这里的语法问题?我需要内部函数来评估通道和值。

我知道所提供的代码由于异步回调而无法工作。我似乎无法为 onreadystatechange 函数获取正确的范围语法。如果我可以为我遇到的问题提供更多说明,请告诉我。谢谢。

function setDio(channel, value) {
    var xmlhttp = new XMLHttpRequest();
    xmlhttp.onreadystatechange = (function(channel,value) { return function(){
        if (this.readyState === 4)
  {
   if (this.status === 200) {
    document.getElementById('ok-msg').innerHTML = 'Digital Output successfully set to '+value+'.';
    document.getElementById('ok-alert').style.display = 'block';
    if(value===1)
    {
     document.getElementById('dio'+channel+'-high').class = 'ibradioactive';
     document.getElementById('dio'+channel+'-low').class = 'ibradioinactive';
     document.getElementById('dio'+channel+'-low').onclick = function(){ setDio(channel,0);};;
     document.getElementById('dio'+channel+'-high').onclick = function(){} ;;
    }
    else
    {
     document.getElementById('dio'+channel+'-high').class = 'ibradioinactive';
     document.getElementById('dio'+channel+'-low').class = 'ibradioactive';
     document.getElementById('dio'+channel+'-high').onclick = function(){ setDio(channel,1);};;
     document.getElementById('dio'+channel+'-low').onclick = function(){} ;;
    }
   }
   else
   {
    document.getElementById('error-msg').innerHTML = 'Digital Output set failed ('+ this.status +'): '+this.responseText;
    document.getElementById('error-alert').style.display = 'block';
   }
        }
    };})(channel,value);
    xmlhttp.open('POST', '/dio/' + channel, true);
    xmlhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
    xmlhttp.send('dio-value=' + value);
}
.alert,.ok-alert,.error-alert,.info-alert,.warning-alert {
font-family:arial;
font-weight:700;
color:#FFF;
margin-bottom:15px;
border-radius:20px;
padding:20px;
display:none;
}

.ok-alert {
background-color:#4CAF50;
}

.error-alert {
background-color:#f44336;
}

.info-alert {
background-color:#2196F3;
}

.warning-alert {
background-color:#ff9800;
}

.alert-close {
margin-left:15px;
color:#FFF;
font-weight:700;
float:right;
font-size:22px;
line-height:20px;
cursor:pointer;
transition:.3s;
}

.inner-group {
display:inline-block;
border:0 solid #000;
font-family:arial;
font-weight:700;
font-size:12pt;
background:#ccc;
border-radius:15px;
vertical-align:text-top;
box-shadow:4px 4px 10px #66a;
margin:10px;
padding:10px 4px;
transition:1s;
}
.ibradioactive {
background:#11AF11;
}

.ibradioactive span {
color:#fff;
}

.ibradioinactive span {
color:#000;
}

.ibradioinactive {
background:#ddd;
}

.ibradioinactive:hover {
background-color:#acf;
}

.ibradio,.ibradioactive,.ibradioinactive {
width:50px;
height:50px;
cursor:pointer;
box-shadow:3px 3px 2px #000;
-webkit-box-shadow:3px 3px 2px #000;
-moz-box-shadow:3px 3px 2px #000;
font-weight:700;
color:#000;
border-radius:40px;
border:1px solid #999;
margin:10px 10px 10px 20px;
padding:5px;
}
label {
display:inline-block;
width:125px;
padding:3px 10px;
}
<div id="error-alert" class="error-alert">
  <span class="alert-close" onclick="this.parentElement.style.display='none';">&times;</span> 
  <span id="error-msg">This is an error alert box.</span>
</div>
<div id="ok-alert" class="ok-alert">
  <span class="alert-close" onclick="this.parentElement.style.display='none';">&times;</span> 
  <span id="ok-msg">This is a success alert box.</span>
</div>
<div id="info-alert" class="info-alert">
  <span class="alert-close" onclick="this.parentElement.style.display='none';">&times;</span> 
  <span id="info-msg">This is an info alert box.</span>
</div>
<div id="warning-alert" class="warning-alert">
  <span class="alert-close" onclick="this.parentElement.style.display='none';">&times;</span> 
  <span id="warning-msg">This is an warning alert box.</span>
</div>
<br />

<div class="inner-group" style="width:550px;">
<label class="l2">Digital I/O #1</label><br>
<label class="l2" style="width:175px">Mode: OUTPUT</label><br />
<label class="l2">New State:</label>
<button class ="ibradioactive" type="submit" id="dio1-high" name="dio1-high" onclick="setDio(1,1)"><span>HIGH</span></button>
<button class ="ibradioinactive" type="submit" id="dio1-low" name="dio1-low" onclick="setDio(1,0)"><span>LOW</span></button>
</div>

编辑:

这是我的原始代码的简化版本,它不起作用:

function setDio(channel, value) {
  var xmlhttp = new XMLHttpRequest();
  xmlhttp.onreadystatechange = function() {
    if (this.readyState === 4)
    {
      if (this.status === 200) {
        if(value === 1)
        {
          document.getElementById('dio'+channel+'-high').class = 'ibradioactive';
          document.getElementById('dio'+channel+'-low').class = 'ibradioinactive';
        }
        else
        {
          document.getElementById('dio'+channel+'-high').class = 'ibradioinactive';
          document.getElementById('dio'+channel+'-low').class = 'ibradioactive';
        }
      }
    }
  };
  xmlhttp.open('POST', '/dio/' + channel, true);
  xmlhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
  xmlhttp.send('dio-value=' + value);
}

因为它不起作用,我尝试重新确定范围并添加闭包以确保该函数正在评估调用时使用的参数值而不是获取默认值。

classes 没有按预期更改,事实上,异步请求实际上并没有被服务器接收。那么,有人能看出为什么这个特定功能不能正常工作吗?我有类似的功能,只是成功地更新了简单的 innerHTML 值。但是,更改 class 似乎不起作用。

编辑 2:

所以,我发现了部分问题。 class 没有改变的原因是我试图用文本而不是对象设置 class。更改为 className 似乎已经解决了这个问题。我也回去不使用任何额外的闭包范围,它现在可能工作正常。仍在进行测试以验证所有更改。

我不确定为什么需要定义显式闭包..

xmlhttp.onreadystatechange = function() { 
  console.log(channel); // parent function parameter can still be accessed here.
}