我有一个存储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根本不支持这种转换。
其他回答
一元的+运算符会处理这些:
var test = true;
// +test === 1
test = false;
// +test === 0
您自然希望在存储它之前在服务器上检查它,因此在服务器上执行此操作可能是一个更明智的地方。
依我看,最好的解决办法是:
fooBar | 0
这在asm.js中用于强制整型。
+ ! !允许你对一个变量应用这个,即使它是未定义的:
+!!undefined // 0
+!!false // 0
+!!true // 1
+!!(<boolean expression>) // 1 if it evaluates to true, 0 otherwise
输入的方法是:
Number(true) // 1
Number(false) // 0
我只是在我写的一些代码中处理这个问题。我的解决方案是使用一个位和。
var j = bool & 1;
处理常量问题的一个更快的方法是创建一个函数。它更便于其他人阅读,更便于在维护阶段理解,并消除了编写错误的可能性。
function toInt( val ) {
return val & 1;
}
var j = toInt(bool);
编辑- 2014年9月10日
在Chrome中,由于某些原因,使用三元操作符和相同的to操作符的转换速度更快。不知道为什么它更快,但我认为这是某种低级优化,在某个地方是有意义的。
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;
}});
推荐文章
- Java整数到字节数组
- 如何清除所有<div>的内容在一个父<div>?
- 检测用户何时离开网页的最佳方法?
- 当“模糊”事件发生时,我如何才能找到哪个元素的焦点去了*到*?
- React不会加载本地图像
- 如何将Blob转换为JavaScript文件
- 在另一个js文件中调用JavaScript函数
- 如何在svg元素中使用z索引?
- 如何求一个数的长度?
- 跨源请求头(CORS)与PHP头
- 如何用Express/Node以编程方式发送404响应?
- parseInt(null, 24) === 23…等等,什么?
- JavaScript变量声明在循环外还是循环内?
- 元素在“for(…in…)”循环中排序
- 在哪里放置JavaScript在HTML文件?