按位与运算符如何作用于 javascript 中的对象?

How does bitwise-and operator work on objects in javascript?

我正在从事一个开源项目,无意中发现了按位运算符。我确实理解这些原则,而且 javascript 将非零整数值评估为 true(如果我错了,请在此处纠正我;在另一个接受的答案中找到此语句post).

问题代码如下:

function example(){
  var args = arguments;
  var j = 1 & args[0];
  .
  .
  .
}

var test = {keyA: 1, keyB: 2};
example(test);

我的问题是:j 的值是多少?

对象的二进制等价物是什么?

据我了解,j = 0 如果 test 中的最后一位为 0,j = 1 如果 test 中的最后一位为 1。

请大家帮帮我。我花了最后一个小时在这里搜索任何几乎相关的 post,大多数主题都是关于数字的,一两个是关于布尔值的,仅此而已。

编辑: 由于上面给出的代码示例似乎并不像我想的那么清楚,这里是我发现的(和工作的)完整功能:

function Extend() {
    var args = arguments;
    var target;
    var options;
    var propName;
    var propValue;
    var deep = 1 & args[0];
    var i = 1 + deep;
    target = args[i - 1] || {};

    for (; i < args.length; i++) {
        // Only deal with non-null/undefined values
        if (options = args[i]) {
            // Extend the base object
            for (propName in options) {
                propValue = options[propName];

                if (propValue !== undefined) {
                    propValue = options[propName];
                    target[propName] = (deep && IsPlainObject(target[propName])) ? Extend(deep, {}, propValue) : propValue;
                }
            }
        }
    }

    // Return the modified object
    return target;
}

var _someVariable = Extend({keyA: 1, keyB: 2, keyC: 10}, _someOtherVariable);

deep必须有一些意义,因为它决定是否进入FOR循环...或不。

按位运算符确实适用于 32 位(无)符号整数。如果你传入任何不是数字的东西,它就会被隐式地强制转换为一个数字。这是像往常一样使用对象的 valueOf/toString 方法完成的,对于您的对象 {keyA: 1, keyB:2} 将产生 NaN。然后,这个数字被转换为 (U)int32,它为 NaN.

给出 0

检查 spec for toUint32,跟随它到 ToNumber 并从那里继续。

deep 变量的目的是检测这两个调用之间的区别:

Extend({keyA: {a: 1}, keyB: 2}, {keyC: 3, keyA: {b: 2}});

Extend(true, {keyA: {a: 1}, keyB: 2}, {keyC: 3, keyA: {b: 2}});

第一个变体将 return 这个:

{keyA: {b: 2}, keyB: 2, keyC: 3}

第二个是为了return这个:

{keyA: {a: 1, b: 2}, keyB: 2, keyC: 3}

所以该函数实际上允许第一个可选参数,这将使该函数递归地应用扩展,因此您得到一个深而不是浅的扩展对象。 您还可以通过分析递归调用来了解此意图,其中第一个参数是 deep,第二个是要扩展的对象,第三个是要扩展的对象。 以下行也显示了这一点:

var i = 1 + deep;

因为 i 是循环开始的点,你可以看到如果 deep 设置为 1 而不是 0,循环将从参数 #2 开始处理,这这是有道理的,因为参数 #0 被认为是可选参数,下一个是目标对象。 请注意,该函数接受可变数量的附加参数,它将用于扩展目标对象。 i 变量循环基于这些参数。

附带说明:由于错误,第二个版本 return 与第一个版本相同。要修复错误,请替换

target[propName] = (deep && IsPlainObject(target[propName]))
    ? Extend(deep, {}, propValue) : propValue;

与:

target[propName] = (deep && IsPlainObject(target[propName]))
    ? Extend(deep, target[propName], propValue) : propValue;

现在,进入本质:

var deep = 1 & args[0];

按位运算符的使用一定是一种让效率高于清晰度的想法。目的是如果第一个参数表示可选参数,则将 deep 设置为 1,该可选参数应该是一个布尔值,指示扩展应该发生在浅层还是深层。由于对象将使该表达式的计算结果为 0,这似乎是一个不错的技巧。 但这有一个问题。如果有人想这样做:

Extend(["3"], {myattr: 2});

人们希望得到一个带有额外自定义项的类似数组的对象 属性 myattr:

{0: "3", length: 1, myattr: 2}

但是,当前的 Extend 函数会将第一个参数误解为执行深度扩展的指令。这是因为 1 & ["3"] 将计算为 1 & 3,计算结果为 1。因此结果将是第二个参数,不会发生任何扩展:

{myattr: 2}

结论:最好避免这种含糊不清的按位运算符的使用,而应该这样做:

var deep = args.length > 0 && typeof args[0] === 'boolean' && args[0];

通俗地说:让 deep 为真 (1) 当至少有一个参数并且该参数是布尔值且其值为真时。在所有其他情况下,让它为假 (0)。 请注意,不能将 false 作为第一个参数传递,认为这会使函数执行浅扩展。在这种情况下, 该参数将被视为要扩展的对象,这将失败。因此,可选的第一个参数(如果提供)必须是值为 true 的布尔值。 这对于原始 Extend 函数和更正后的函数都是如此。

最后,最好为该函数添加注释以阐明第一个可选参数的用法。