按位与运算符如何作用于 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
函数和更正后的函数都是如此。
最后,最好为该函数添加注释以阐明第一个可选参数的用法。
我正在从事一个开源项目,无意中发现了按位运算符。我确实理解这些原则,而且 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
函数和更正后的函数都是如此。
最后,最好为该函数添加注释以阐明第一个可选参数的用法。