Number
constructor, unary +
; use a simple if
all the time; resort to bool | 0
or 1 * bool
if benchmarks in your project do better this way.This is quite an old question, and there exist many valid answers. Something I've noticed is that all benchmarks here are irrelevant - none take into account branch prediction. Also, nowadays, JS engines don't simply interpret the code, they JIT compile it to native machine code and optimize it prior to execution. This means that, besides branch prediction, the compiler can even substitute expressions with their final value.
Now, how do these 2 factors affect the performance of, well, boolean to integer conversion? Let's find out! Before we get into the benchmarks, it is important to know what we benchmark. For the conversion, we're using the following seven conversion methods:
Number(bool)
bool ? 1 : 0
+
: +bool
bool | 0
bool & 1
~~bool
bool * 1
"Conversion" means converting false
to 0
and true
to 1
1. Each conversion method is ran 100000 times, measuring operations/millisecond. In the following tables, conversion methods will be grouped to their results accordingly. The results are from my machine, which features an AMD Ryzen 7 4800HS as its CPU.
The first benchmark converts the constant true
:
Method | Edge/Chromium (V8) | Firefox (Spidermonkey) |
---|---|---|
Number(bool) |
83103 | 1088 |
bool ? 1 : 0 |
83073 | 7732 |
+bool |
83372 | 1043 |
bool | 0 |
83479 | 9344 |
bool & 1 |
83242 | 9354 |
~~bool |
83293 | 9316 |
bool * 1 |
83504 | 9316 |
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. What are the takeaways? Chrome browsers 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.
That above isn't a situation we'll ever encounter in real projects. So let's change our variables: the bool is now Math.random() < 0.5
. This yields a 50% chance of true
, 50% of false
. Do our results change? Let's run this benchmark to see.
Method | Edge/Chromium (V8) | Firefox (Spidermonkey) |
---|---|---|
Number(bool) |
2405 | 662 |
bool ? 1 : 0 |
1482 | 1580 |
+bool |
2386 | 673 |
bool | 0 |
2391 | 2499 |
bool & 1 |
2409 | 2513 |
~~bool |
2341 | 2493 |
bool * 1 |
2398 | 2518 |
The results are more consistent now. We see similar numbers for ternary if, bitwise, and multiplication methods, but the Number
constructor and unary +
perform better on V8. We can presume from the numbers that V8 replaces them with whatever instructions it's using for the bitwise tricks, but in Spidermonkey those functions do all the work.
We haven't still tackled one factor we mentioned above: branch prediction. Let's change, in this benchmark, our boolean variable to Math.random() < 0.01
, which means 1% true
, 99% false
.
Method | Edge/Chromium (V8) | Firefox (Spidermonkey) |
---|---|---|
Number(bool) |
2364 | 865 |
bool ? 1 : 0 |
2352 | 2390 |
+bool |
2447 | 777 |
bool | 0 |
2421 | 2513 |
bool & 1 |
2400 | 2509 |
~~bool |
2446 | 2501 |
bool * 1 |
2421 | 2497 |
Unexpected? Expected? I'd say the latter, because in this case branch prediction was successful in almost all cases, given the tiny difference between the ternary if and bitwise hacks. All other results are the same, not much else to say here.
This endeavour brings us back to the original question: how to convert bool to int in Javascript? Here are my suggestions:
Number(bool)
and +bool
. These 2 methods do a lot of work under the hood, and even though Chrome managed to optimize them in our benchmarks, Firefox did not, and there might be some situations where these optimizations won't be done by the compiler. Besides that, not everyone's on Chrome! I still have to put up with that, don't you?...if (bool)
instead of that ugly ternary! I wish Javascript had what Rust or Python have...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.I will be forever grateful to you for reading until the end - this is my first longer, significant StackOverflow answer and it means the world to me if it's been helpful and insightful. If you find any errors, feel free to correct me!