我有一个存储 false
或 true
的变量,但我分别需要 0
或 1
。我怎样才能做到这一点?
bool === true ? 1 : 0
,因为它是迄今为止 V8 中最快的。
bool ? 1 : 0;
使用 unary +
operator,它将其操作数转换为数字。
+ true; // 1
+ false; // 0
当然,请注意,您仍然应该清理服务器端的数据,因为无论客户端代码怎么说,用户都可以将任何数据发送到您的服务器。
Javascript 有一个可以使用的三元运算符:
var i = result ? 1 : 0;
NaN
。所以如果你想要L33T并保证输入,那就去urary,否则我认为三元+真值测试是最好的。
if
语句。
恕我直言,最好的解决方案是:
fooBar | 0
这在 asm.js 中用于强制整数类型。
1
整数吗?
1 | 0 = 1; 0 | 0 = 0; true | 0 = 1; false | 0 = 0; 'foo' | 0 = 0; undefined | 0 = 0
The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.
我更喜欢使用 Number function。它接受一个对象并将其转换为一个数字。
例子:
var myFalseBool = false;
var myTrueBool = true;
var myFalseInt = Number(myFalseBool);
console.log(myFalseInt === 0);
var myTrueInt = Number(myTrueBool);
console.log(myTrueInt === 1);
您可以在 jsFiddle 中对其进行测试。
键入的方法是:
Number(true) // 1
Number(false) // 0
我创建了所有建议答案的 JSperf 比较。
TL;DR - 当前所有浏览器的最佳选择是:
val | 0;
.
更新:
现在看起来它们都非常相似,除了 Number()
函数是最慢的,而最好的是 val === true ? 1 : 0;
。
我今天才发现这个快捷方式。
~~(真实)
~~(假)
人们比我能解释的聪明得多:
http://james.padolsey.com/javascript/double-bitwise-not/
当 JavaScript 需要一个数字值但接收到一个布尔值时,它会将该布尔值转换为一个数字:true 和 false 分别转换为 1 和 0。所以你可以利用这一点;
变量 t = 真;变量 f = 假;控制台.log(t*1); // t*1 === 1 console.log(f*1); // f*1 === 0 console.log(+t); // 0+t === 1 或缩短为 +t === 1 console.log(+f); //0+f === 0 或缩短为 +f === 0
进一步阅读 The Definitive Guide to Javascript 的类型转换第 3.8 章。
TL;DR:避免使用 Number 构造函数和 +bool;默认情况下使用简单的 if;诉诸布尔| 0, 1 * bool 如果您的项目中的基准以这种方式做得更好。
这是一个相当古老的问题,并且存在许多有效的答案。我注意到这里的所有基准都是无关紧要的 - 没有一个考虑到 branch prediction。此外,如今,JS 引擎不只是解释代码,它们JIT compile 将其转换为本地机器代码并在执行之前对其进行优化。这意味着,除了分支预测之外,编译器甚至可以用它们的最终值替换表达式。
现在,这两个因素如何影响布尔到整数转换的性能?让我们来了解一下!在我们进入基准测试之前,了解我们的基准测试是很重要的。对于转换,我们使用以下七种转换方法:
数字构造函数:Number(bool)
If 语句(使用三元): bool ? 1 : 0
一元运算符 +: +bool
按位或:布尔 | 0
按位与:布尔 & 1
按位双非:~~bool
数字乘法:bool * 1
“转换”是指将 false
转换为 0
并将 true
转换为 1
1。每种转换方法运行 100000 次,测量操作/毫秒。在下表中,转换方法将相应地分组到它们的结果中。结果后面的百分比表示此方法与同一浏览器中最快的方法相比有多慢。如果没有百分比,则该方法要么是最快的,要么差异可以忽略不计(<0.01%)。基准测试在配备 Apple M1 Pro 10 核 CPU 和 16GB RAM 的 Macbook Pro 16 英寸机器上运行。浏览器是 Chrome 102、Firefox 101 和 Safari 15.5。
第一个 benchmark 转换常量 true
:
方法 Chrome (V8) Firefox (Spidermonkey) Safari (Webkit) Number(bool) 31745.89 392.35 - 91.48% 31231.79 bool ? 1 : 0 31592.8 - 0.48% 4602.64 27533.47 - 11.84% + 布尔值 31332.57 - 1.3% 4463.41 - 3.02% 27378.7 - 12.34% 布尔值 | 0 31488.5 - 0.81% 4441.4 - 3.5% 27222 - 12.84% bool & 1 31383.17 - 1.14% 4459.64 - 3.11% 27317.41 - 12.53% ~~bool 31265.85 - 1.51% 4442.35 - 3.48% 27434.72 - 12.16% bool * 1 31374.4 - 1.17% 4444.05 - 3.45% 27381.19 - 12.33%
有趣的! V8 显示了一些巨大的数字,所有数字都大致相同! Spidermonkey 并没有真正发光,但我们可以看到按位和乘法技巧排在第一位,三进制 if 排在第二位。最后,Webkit 的 Number
与 V8 类似,其他方法落后,但都彼此接近。有什么外卖?浏览器大多设法用简单的值 1
替换我们的转化。这种优化将发生在我们可以将布尔值替换为恒定值的地方。 Number
构造函数是一个有趣的异常 - 它在 Firefox 中严重落后(91% 慢!),而在 Safari 中它是最快的!
以上不是我们在实际项目中会遇到的情况。所以让我们改变我们的变量:bool 现在是 Math.random() < 0.5
。这产生 true
的 50% 的机会,false
的 50%。我们的结果会改变吗?让我们运行这个 benchmark 来看看。
方法 Chrome (V8) Firefox (Spidermonkey) Safari (Webkit) Number(bool) 1648.83 - 2.26% 280.34 - 86.4% 8014.69 bool ? 1 : 0 804.27 - 52.32% 731.57 - 64.5% 1294.02 - 83.85% + 布尔值 1670.79 - 0.95% 2057.94 7753.99 - 3.25% 布尔值 | 0 1668.22 - 1.11% 2054.17 7764.81 - 3.12% bool & 1 1675.52 - 0.67% 2056.76 7193.08 - 10.25% ~~bool 1676.24 - 0.63% 2056.18 7669.48 - 4.31% bool * 1 1686.88 2060.88 7751.48 - 3.28%
现在的结果更加一致。我们看到跨浏览器的三元 if、按位和乘法方法的数字相似,Number
构造函数再次在 Firefox 上执行最差。三元落在后面,因为它会生成分支。 Safari 似乎是我们总体上表现最好的,每种方法都产生了惊人的快速结果!
现在让我们看看分支预测如何通过以下 benchmark 影响我们的结果,我们将布尔变量更改为 Math.random() < 0.01
,这意味着 1% true
,99% false
。
方法 Chrome (V8) Firefox (Spidermonkey) Safari (Webkit) Number(bool) 1643.13 - 1.68% 280.06 - 86.4% 8071.65 bool ? 1 : 0 1590.55 - 4.83% 1970.66 - 4.32% 7119.59 - 11.8% + 布尔值 1662.09 - 0.55% 2054.09 7762.03 - 3.84% 布尔值 | 0 1669.35 2051.85 7743.95-4.06%布尔&1 1661.09-0.61%2057.62 7454.45-7.65%~~ bool 1662.94-0.5%2059.65 7739.4-4.12% - 4.12%BOOL * 1 1671.28 2048.87777787.38.38.38.38.38.87.87.887.887.88.88.88.88. bool。38.38.38.38.38.87.87.88.88.88.88.88. bool。38.38.38.38.38.87.88.88.88.88.88. bool。38.38.38.38.38.87.88.88.88.88.88. bool。
意外?预期的?我会说后者,因为在这种情况下,分支预测在几乎所有情况下都是成功的,因为三元 if 和按位黑客之间的差异较小。其他结果都是一样的,这里不多说。我仍然会指出 Firefox 中 Number
的可怕性能 - 为什么?
这一努力让我们回到了最初的问题:如何在 Javascript 中将 bool 转换为 int?以下是我的建议:
通常使用 if 语句。不要变得聪明——浏览器通常会做得更好,而且通常意味着大多数情况。它们是这里所有方法中最易读和最清晰的。当我们处于可读性时,也许使用 if (bool) 而不是那个丑陋的三元!我希望 Javascript 拥有 Rust 或 Python 所拥有的...
真正需要时使用其余部分。也许您项目中的基准测试执行不合标准,并且您发现令人讨厌的 if 会导致性能不佳 - 如果是这种情况,请随意进入无分支编程!但是不要在那个兔子洞里走得太深,相信我,没有人会从 -1 * (a < b) + 1 * (a > b) 之类的东西中受益。
还有一些细节:
避免数字(布尔)。虽然 Chromium 平台(Chrome + Edge)在全球拥有约 68% 的市场份额,Safari 为 19%,Firefox 仅为 3.6%,但仍有足够多的其他快速执行的方法不会完全牺牲一部分用户. Firefox 拥有 7% 的桌面市场份额,相当于 1.73 亿用户。
在较旧的基准测试中,+bool 的性能与 Firefox 中的 Number 相似,可能也要考虑到这一点 - 按位 hack 和乘法在所有情况下在所有浏览器中提供一致的性能结果。布尔 | 0 最有可能让其他开发人员熟悉。
我将永远感谢您阅读到最后——这是我第一个更长的、重要的 StackOverflow 答案,如果它有帮助和有见地,它对我来说意味着世界。如果您发现任何错误,请随时纠正我!
编辑:以前的基准测试工具提供了模糊的结果,没有衡量单位。我已经更改了它,还添加了 Safari 的基准,这影响了结论。
定义了转换,因为不清楚布尔到整数的含义。例如,Go 根本不支持这种转换。
start=performance.now(); for (let i = 0; i < 1000000; i++) {let x = +(Math.random()<0.5);} end=performance.now(); console.log(end-start)
。我在误解什么?
一元 +
运算符将处理此问题:
var test = true;
// +test === 1
test = false;
// +test === 0
您自然会希望在存储之前在服务器上对其进行完整性检查,因此无论如何这可能是一个更明智的地方。
===
,因为即使没有“显式转换 :-) true === 1
也是假的,true == 1
也是假的。
我只是在我正在编写的一些代码中处理这个问题。我的解决方案是使用按位和。
var j = bool & 1;
处理持续问题的更快方法是创建一个函数。其他人可读性更高,在维护阶段更易于理解,并消除了编写错误的可能性。
function toInt( val ) {
return val & 1;
}
var j = toInt(bool);
编辑 - 2014 年 9 月 10 日
出于某种原因,在 Chrome 中使用与运算符相同的三元运算符进行的转换不会更快。对于为什么它更快没有意义,但我认为这是某种低级优化,在此过程中的某个地方是有意义的。
var j = boolValue === true ? 1 : 0;
自己测试:http://jsperf.com/boolean-int-conversion/2
在 FireFox 和 Internet Explorer 中,使用我发布的版本通常更快。
编辑 - 2017 年 7 月 14 日
好的,我不会告诉你应该或不应该使用哪一个。每个该死的浏览器在使用每种方法执行操作的速度上一直在上下波动。 Chrome 在某一时刻实际上让按位 & 版本比其他版本做得更好,但后来突然变得更糟了。我不知道他们在做什么,所以我将把它留给谁在乎。很少有理由关心这样的操作完成得有多快。即使在移动设备上,它也是一项无操作。
另外,这里有一个更新的方法来添加一个不能被覆盖的“toInt”原型。
Object.defineProperty(Boolean.prototype, "toInt", { value: function()
{
return this & 1;
}});
您还可以添加 0,使用移位运算符或异或:
val + 0;
val ^ 0;
val >> 0;
val >>> 0;
val << 0;
这些具有与其他答案相似的速度。
在我的上下文中,我从布尔值获取不透明度值的 React Native,最简单的方法是:使用一元 + 运算符。
+ true; // 1
+ false; // 0
这会将布尔值转换为数字;
style={ opacity: +!isFirstStep() }
+!!
允许您将其应用于变量,即使它是 undefined
:
+!!undefined // 0
+!!false // 0
+!!true // 1
+!!(<boolean expression>) // 1 if it evaluates to true, 0 otherwise
您可以通过简单地扩展布尔原型来做到这一点
Boolean.prototype.intval = function(){return ~~this}
理解那里发生的事情并不容易,所以一个替代版本将是
Boolean.prototype.intval = function(){return (this == true)?1:0}
完成了你可以做的事情
document.write(true.intval());
当我使用布尔值来存储条件时,我经常将它们转换为位域,在这种情况下,我最终会使用原型函数的扩展版本
Boolean.prototype.intval = function(places)
{
places = ('undefined' == typeof(places))?0:places;
return (~~this) << places
}
你可以用它做
document.write(true.intval(2))
它产生 4 作为其输出。
let integerVariable = booleanVariable * 1;
尝试
val*1
让 t=true;让 f=false;控制台.log(t*1);控制台.log(f*1)
我已经测试了所有这些示例,我做了一个基准测试,最后我建议您选择较短的,它不会影响性能。
在 Ubuntu 服务器 14.04、nodejs v8.12.0 - 26/10/18 中运行
let i = 0;
console.time("TRUE test1")
i=0;
for(;i<100000000;i=i+1){
true ? 1 : 0;
}
console.timeEnd("TRUE test1")
console.time("FALSE test2")
i=0;
for(;i<100000000;i=i+1){
false ? 1 : 0;
}
console.timeEnd("FALSE test2")
console.log("----------------------------")
console.time("TRUE test1.1")
i=0;
for(;i<100000000;i=i+1){
true === true ? 1 : 0;
}
console.timeEnd("TRUE test1.1")
console.time("FALSE test2.1")
i=0;
for(;i<100000000;i=i+1){
false === true ? 1 : 0;
}
console.timeEnd("FALSE test2.1")
console.log("----------------------------")
console.time("TRUE test3")
i=0;
for(;i<100000000;i=i+1){
true | 0;
}
console.timeEnd("TRUE test3")
console.time("FALSE test4")
i=0;
for(;i<100000000;i=i+1){
false | 0;
}
console.timeEnd("FALSE test4")
console.log("----------------------------")
console.time("TRUE test5")
i=0;
for(;i<100000000;i=i+1){
true * 1;
}
console.timeEnd("TRUE test5")
console.time("FALSE test6")
i=0;
for(;i<100000000;i=i+1){
false * 1;
}
console.timeEnd("FALSE test6")
console.log("----------------------------")
console.time("TRUE test7")
i=0;
for(;i<100000000;i=i+1){
true & 1;
}
console.timeEnd("TRUE test7")
console.time("FALSE test8")
i=0;
for(;i<100000000;i=i+1){
false & 1;
}
console.timeEnd("FALSE test8")
console.log("----------------------------")
console.time("TRUE test9")
i=0;
for(;i<100000000;i=i+1){
+true;
}
console.timeEnd("TRUE test9")
console.time("FALSE test10")
i=0;
for(;i<100000000;i=i+1){
+false;
}
console.timeEnd("FALSE test10")
console.log("----------------------------")
console.time("TRUE test9.1")
i=0;
for(;i<100000000;i=i+1){
0+true;
}
console.timeEnd("TRUE test9.1")
console.time("FALSE test10.1")
i=0;
for(;i<100000000;i=i+1){
0+false;
}
console.timeEnd("FALSE test10.1")
console.log("----------------------------")
console.time("TRUE test9.2")
i=0;
for(;i<100000000;i=i+1){
-true*-1;
}
console.timeEnd("TRUE test9.2")
console.time("FALSE test10.2")
i=0;
for(;i<100000000;i=i+1){
-false*-1;
}
console.timeEnd("FALSE test10.2")
console.log("----------------------------")
console.time("TRUE test9.3")
i=0;
for(;i<100000000;i=i+1){
true-0;
}
console.timeEnd("TRUE test9.3")
console.time("FALSE test10.3")
i=0;
for(;i<100000000;i=i+1){
false-0;
}
console.timeEnd("FALSE test10.3")
console.log("----------------------------")
console.time("TRUE test11")
i=0;
for(;i<100000000;i=i+1){
Number(true);
}
console.timeEnd("TRUE test11")
console.time("FALSE test12")
i=0;
for(;i<100000000;i=i+1){
Number(false);
}
console.timeEnd("FALSE test12")
console.log("----------------------------")
console.time("TRUE test13")
i=0;
for(;i<100000000;i=i+1){
true + 0;
}
console.timeEnd("TRUE test13")
console.time("FALSE test14")
i=0;
for(;i<100000000;i=i+1){
false + 0;
}
console.timeEnd("FALSE test14")
console.log("----------------------------")
console.time("TRUE test15")
i=0;
for(;i<100000000;i=i+1){
true ^ 0;
}
console.timeEnd("TRUE test15")
console.time("FALSE test16")
i=0;
for(;i<100000000;i=i+1){
false ^ 0;
}
console.timeEnd("FALSE test16")
console.log("----------------------------")
console.time("TRUE test17")
i=0;
for(;i<100000000;i=i+1){
true ^ 0;
}
console.timeEnd("TRUE test17")
console.time("FALSE test18")
i=0;
for(;i<100000000;i=i+1){
false ^ 0;
}
console.timeEnd("FALSE test18")
console.log("----------------------------")
console.time("TRUE test19")
i=0;
for(;i<100000000;i=i+1){
true >> 0;
}
console.timeEnd("TRUE test19")
console.time("FALSE test20")
i=0;
for(;i<100000000;i=i+1){
false >> 0;
}
console.timeEnd("FALSE test20")
console.log("----------------------------")
console.time("TRUE test21")
i=0;
for(;i<100000000;i=i+1){
true >>> 0;
}
console.timeEnd("TRUE test21")
console.time("FALSE test22")
i=0;
for(;i<100000000;i=i+1){
false >>> 0;
}
console.timeEnd("FALSE test22")
console.log("----------------------------")
console.time("TRUE test23")
i=0;
for(;i<100000000;i=i+1){
true << 0;
}
console.timeEnd("TRUE test23")
console.time("FALSE test24")
i=0;
for(;i<100000000;i=i+1){
false << 0;
}
console.timeEnd("FALSE test24")
console.log("----------------------------")
console.time("TRUE test25")
i=0;
for(;i<100000000;i=i+1){
~~true;
}
console.timeEnd("TRUE test25")
console.time("FALSE test26")
i=0;
for(;i<100000000;i=i+1){
~~false;
}
console.timeEnd("FALSE test26")
console.log("----------------------------")
console.time("TRUE test25.1")
i=0;
for(;i<100000000;i=i+1){
~true*-1-1;
}
console.timeEnd("TRUE test25.1")
console.time("FALSE test26.1")
i=0;
for(;i<100000000;i=i+1){
~false*-1-1;
}
console.timeEnd("FALSE test26.1")
console.log("----------------------------")
console.time("TRUE test27")
i=0;
for(;i<100000000;i=i+1){
true/1;
}
console.timeEnd("TRUE test27")
console.time("FALSE test28")
i=0;
for(;i<100000000;i=i+1){
false/1;
}
console.timeEnd("FALSE test28")
结果
TRUE test1: 93.301ms
FALSE test2: 102.854ms
----------------------------
TRUE test1.1: 118.979ms
FALSE test2.1: 119.061ms
----------------------------
TRUE test3: 97.265ms
FALSE test4: 108.389ms
----------------------------
TRUE test5: 85.854ms
FALSE test6: 87.449ms
----------------------------
TRUE test7: 83.126ms
FALSE test8: 84.992ms
----------------------------
TRUE test9: 99.683ms
FALSE test10: 87.080ms
----------------------------
TRUE test9.1: 85.587ms
FALSE test10.1: 86.050ms
----------------------------
TRUE test9.2: 85.883ms
FALSE test10.2: 89.066ms
----------------------------
TRUE test9.3: 86.722ms
FALSE test10.3: 85.187ms
----------------------------
TRUE test11: 86.245ms
FALSE test12: 85.808ms
----------------------------
TRUE test13: 84.192ms
FALSE test14: 84.173ms
----------------------------
TRUE test15: 81.575ms
FALSE test16: 81.699ms
----------------------------
TRUE test17: 81.979ms
FALSE test18: 81.599ms
----------------------------
TRUE test19: 81.578ms
FALSE test20: 81.452ms
----------------------------
TRUE test21: 115.886ms
FALSE test22: 88.935ms
----------------------------
TRUE test23: 82.077ms
FALSE test24: 81.822ms
----------------------------
TRUE test25: 81.904ms
FALSE test26: 82.371ms
----------------------------
TRUE test25.1: 82.319ms
FALSE test26.1: 96.648ms
----------------------------
TRUE test27: 89.943ms
FALSE test28: 83.646ms
不定期副业成功案例分享
Number()
甚至更慢。bool === true ? 1 : 0
似乎是最快的,紧随bool | 0
之后。