位操作 - 在 JavaScript 中取消设置产生错误值的位

bit manipulation - unsetting bits in javascript producing wrong value

本文关键字:错误 设置 JavaScript 取消 位操作      更新时间:2023-09-26

我有 4 个复选框。如果按下所有 4 个复选框,我想生成 15 Number,例如"0000 1111"。如果未单击任何复选框,则它应生成 0,例如"0000 0000"。换句话说,单击该复选框时,应设置关联的位,否则应取消设置。每个复选框由 2 的幂引发,以针对下一个位:

<input type="checkbox" name="validation_rules" id="inlineCheckbox1" value="1">
<input type="checkbox" name="validation_rules" id="inlineCheckbox2" value="2">
<input type="checkbox" name="validation_rules" id="inlineCheckbox4" value="4">
<input type="checkbox" name="validation_rules" id="inlineCheckbox8" value="8">

我让它工作正常,可以设置位:

以下是相关方法:

listen_for_enabled_change: function(){
  $form.on('click', 'input[name="validation_rules"]', function(){
    var $hidden = $(this).closest('.field-border').find("input[type='hidden'][name='result']");
    var new_val;
    if($(this).get(0).checked) {
      new_val = $hidden.val() | $(this).val();
    } else {
      var mask = 1 << $(this).val()/2;
      new_val = $hidden.val() & ~mask;
    }
    $hidden.val(new_val);
  })
}

不幸的是,取消设置位在上面的代码中不起作用。例如,如果隐藏的输入字段值为 8。然后我取消选中值为 8 的复选框,它应该产生 0。但是,它根本不会更改值。它只返回Number 8。我可能做错了什么?

我认为你的问题就在这里:

  var mask = 1 << $(this).val()/2;
  new_val = $hidden.val() & ~mask;

这些值是[1,2,4,8]的,这将导致四舍五入的整数为 [0,1,2,4] 。是的,这是一个4,应该是一个3

为什么不将复选框值标记为需要设置的位索引?

<input type="checkbox" name="validation_rules" id="inlineCheckbox1" value="0">
<input type="checkbox" name="validation_rules" id="inlineCheckbox2" value="1">
<input type="checkbox" name="validation_rules" id="inlineCheckbox4" value="2">
<input type="checkbox" name="validation_rules" id="inlineCheckbox8" value="3">

然后你可以:

if($(this).get(0).checked) {
  // flip on the bit at the bit index
  new_val = $hidden.val() | (1 << $(this).val());
} else {
  // flip off the bit at the bit index
  new_val = $hidden.val() & ~(1 << $(this).val());
}

或者整个事情,清理了一下:

var $this = $(this);
var $hidden = $("#result");
var newVal = $hidden.val();
var bit = $this.val()
if (this.checked) {
  newVal = newVal | (1 << bit);
} else {
  newVal = newVal & ~(1 << bit);
}
$hidden.val(newVal);

工作示例:https://jsfiddle.net/zjg2gbp3/3/

在我看来

,基于刚刚选中的复选框进行的所有位屏蔽和移动都是不必要的复杂(过早优化?(,而不是根据刚刚选中的复选框操作当前$hidden值,通过每次更改任何复选框时简单地对值求和,您将获得更具可读性/更不容易出错的代码:

$form.on('change', 'input[name="validation_rules"]', function () {  // 'change' is more robust than 'click' here    
    var new_val = 0;
    $('input[name="validation_rules"]').each(function(i, elem) {
        if (elem.checked) {
            new_val += parseInt(elem.value, 10);
        }
    });
    $hidden.val(new_val);
})

我一定错过了什么,但是...简单的序列化将可以:

您可以将元素集合传递到将添加位掩码的函数中。

var getBitmask = function(els){
    return Array.prototype.reduce.call(Array.prototype.filter.call(els, function(el){
        return el.checked;
    }), function(a, b){
        return {value: ~~a.value + ~~b.value};
    }).value;
};
console.log(getBitmask(document.querySelectorAll('input[type=checkbox]')));

以上在没有jQuery的情况下工作。

您也可以围绕元素索引自动构建位掩码。