我有一个存储false或true的变量,但我需要分别为0或1。我该怎么做呢?


当前回答

TL;DR:避免数字构造函数和+bool;默认情况下使用简单的if;如果项目中的基准测试这样做更好,请使用bool | 0,1 * bool。

这是一个相当老的问题,有很多有效的答案。我注意到这里所有的基准测试都是不相关的——没有一个考虑到分支预测。而且,现在JS引擎不只是简单地解释代码,而是将其JIT编译为本机机器码,并在执行之前对其进行优化。这意味着,除了分支预测,编译器甚至可以用表达式的最终值替换表达式。

那么,这两个因素是如何影响布尔到整数转换的性能的呢?让我们一探究竟!在开始基准测试之前,了解基准测试的对象是很重要的。对于转换,我们使用以下7种转换方法:

数字构造函数:Number(bool) If语句(使用三元):bool ?1:0 一元运算符+:+bool 按位OR: bool | 0 按位AND: bool & 1 位双NOT: ~~bool 数字乘法:bool * 1

"Conversion" means converting false to 0 and true to 11. Each conversion method is ran 100000 times, measuring operations/millisecond. In the following tables, conversion methods will be grouped to their results accordingly. The percentage after the result represents how slow this method is compared to the fastest, in the same browser. If there is no percentage, the method is either the fastest or the difference is negligible (<0.01%). Benchmarks are run on a Macbook Pro 16-inch machine, with the Apple M1 Pro 10-core CPU and 16GB of RAM. Browsers are Chrome 102, Firefox 101 and Safari 15.5.

第一个基准测试转换常量true:

Method 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%
+bool 31332.57 - 1.3% 4463.41 - 3.02% 27378.7 - 12.34%
bool | 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%

Interesting! V8 shows some huge numbers, all of them approximately the same! Spidermonkey doesn't really shine, but we can see that the bitwise and multiplication tricks come first, and the ternary if second. Finally, Webkit's Number does similarly to V8's and the other methods fall behind, but are all close to each other. What are the takeaways? Browsers mostly manage to replace our conversions with simply the value 1. This optimization will take place where we can mentally replace the boolean to a constant value. The Number constructor is an intriguing anomaly - it severly falls behind in Firefox (91% slower!), while in Safari it is the fastest!

上述情况在实际项目中是不会遇到的。所以让我们改变变量:bool值现在是Math.random() < 0.5。这就产生了50%的真概率,50%的假概率。我们的结果会改变吗?让我们运行这个基准测试来看看。

Method 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%
+bool 1670.79 - 0.95% 2057.94 7753.99 - 3.25%
bool | 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似乎是我们整体表现最好的,每种方法都能产生极快的结果!

现在让我们看看分支预测如何影响下面基准测试的结果,其中我们将布尔变量改为Math.random() < 0.01,这意味着1%为真,99%为假。

Method 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%
+bool 1662.09 - 0.55% 2054.09 7762.03 - 3.84%
bool | 0 1669.35 2051.85 7743.95 - 4.06%
bool & 1 1661.09 - 0.61% 2057.62 7454.45 - 7.65%
~~bool 1662.94 - 0.5% 2059.65 7739.4 - 4.12%
bool * 1 1671.28 2048.21 7787.38 - 3.52%

意想不到的?预期?我认为是后者,因为在这种情况下,分支预测在几乎所有情况下都是成功的,因为三元if和位hack之间的差异较小。其他的结果都是一样的,这里就不多说了。我还是要指出数字在Firefox中的糟糕表现——为什么?

这将我们带回到最初的问题:如何在Javascript中将bool类型转换为int类型?以下是我的建议:

Use if statements, in general. Don't get smart - the browser will do better, usually, and usually means most of the situations. They are the most readable and clear out of all the methods here. While we're at readability, maybe use if (bool) instead of that ugly ternary! I wish Javascript had what Rust or Python have... Use the rest when it's truly necessary. Maybe benchmarks in your project perform sub-standard, and you found that a nasty if causes bad performance - if that's the case, feel free to get into branchless programming! But don't go too deep in that rabbit hole, nobody will benefit from things like -1 * (a < b) + 1 * (a > b), believe me.

还有一些细节:

Avoid Number(bool). While it is true that the Chromium platform (Chrome + Edge) has about 68% market share globally, Safari 19% and Firefox a mere 3.6%, there are enough other fast-performing methods that won't fully sacrifice a percentage of your users. Firefox has 7% desktop market share, which amounts to a sizable number of 173 million users. In older benchmarks, +bool performed similarly bad to Number in Firefox, maybe take this in consideration, too - bitwise hacks and multiplication give consistently performant results across all browsers, in all situations. bool | 0 has the best chance to be familiar to other developers.

我将永远感谢你一直读到最后——这是我第一个更长的、重要的StackOverflow回答,如果它有帮助和深刻的见解,对我来说意味着世界。如果你发现任何错误,请随时纠正我!

编辑:之前的基准测试工具提供了模糊的结果,没有一个度量单位。我对它进行了更改,并为Safari添加了基准测试,这对结论产生了影响。


定义了转换,因为它并不真正清楚布尔到整数的含义。例如,Go根本不支持这种转换。

其他回答

我对所有建议的答案创建了一个JSperf比较。

TL;DR -当前所有浏览器的最佳选择是:

val | 0;

.

更新:

似乎这些天它们都是完全相同的,除了Number()函数是最慢的,而最好的val === true ?1: 0;。

当JavaScript期望一个数字值但接收到一个布尔值时,它会将该布尔值转换为一个数字:true和false分别转换为1和0。所以你可以利用这个;

Var t = true; Var f = false; console.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

进一步阅读Javascript权威指南第3.8章的类型转换。

输入的方法是:

Number(true) // 1
Number(false) // 0

在我的上下文中,React Native,我从布尔获取不透明度值,最简单的方法:使用一元+运算符。

+ true; // 1
+ false; // 0

这将布尔值转换为数字;

style={ opacity: +!isFirstStep() }

一元的+运算符会处理这些:

var test = true;
// +test === 1
test = false;
// +test === 0

您自然希望在存储它之前在服务器上检查它,因此在服务器上执行此操作可能是一个更明智的地方。