为什么隐式转换比JS中的显式快得多?隐式铸造是一种好的做法吗?

时间:2016-06-05 22:33:33

标签: javascript performance type-conversion

我知道投射String(1234)Number("1234")等类型更干净,更好,但我只是尝试对同样的事情进行基准测试,特别是"" + 1234 // -> "1234"和{{1 }}

结果非常令人惊讶(对我来说)。我在Chrome中每次迭代100,000次。

我使用了这个简单的代码。

- - "1234"  // -> 1234

var then = Date.now(); for (var i = 0; i < 100000000; ++i) { var a = - - "1234"; }; console.log(Date.now() - then); 花费了2351毫秒,而Number("1234")只花了748毫秒。

同样地,相反,- - "1234"花了3701毫秒,而String(1234)只花了893毫秒。

差异非常大。

我的问题是:是什么使得显式转换比隐式更慢?我的直觉告诉我它应该是另一种方式。

使用隐式强制转换是一种好习惯吗?特别是hacky "" + 1234?有更好的选择吗?

PS:我在Firefox中尝试过相同的功能。它大约慢了500倍(但隐式转换仍然快得多)。到底是怎么回事?它是否与分支预测或类似的东西相关联?我想我的基准测试错了。

2 个答案:

答案 0 :(得分:3)

如果您不使用常量,如果您使用i即时,那么结果将完全不同:

console.time('a');
for (var i = 0; i < 1e7; ++i) {
    var a = String(i);
}; 
console.timeEnd('a');
console.time('b');
for (var i = 0; i < 1e7; ++i) {
    var a = "" + i;
}; 
console.timeEnd('b');

输出:

a: 1062.192ms
b: 884.535ms

注意我也必须删除10的幂。 100000000 === 1e8我使用1e7

这表明,在基准测试中使用常量时会发生很多优化。

现在Number(...)似乎更快了:

console.time('a');
for (var i = 0; i < 1e7; ++i) {
    var a = - - ("" + i);
}; 
console.timeEnd('a');
console.time('b');
for (var i = 0; i < 1e7; ++i) {
    var a = Number("" + i);
}; 
console.timeEnd('b');

输出:

a: 2010.903ms
b: 1557.735ms

答案 1 :(得分:3)

理论上,使用一元+-运算符应该比调用 Number String 更快,因为它们使用内部< em> ToNumber 和 ToString 方法将操作数转换为数字类型,而数字字符串需要额外的函数开销调用

然而,理论并不总是与实践相匹配,因为将Number(x)优化为+x可能非常简单,反之亦然,而编译器认为它更快。

  

是什么使得显式转换比隐式更慢?我的直觉告诉我它应该是另一种方式。

与往常一样,您在特定版本的浏览器中获得的结果不一定适用于其他浏览器甚至同一浏览器的其他版本。理论上,显式转换应该更慢,但我不会依赖于实现。

  

使用隐式强制转换是一种好习惯吗?特别是hacky - - “1234”?有更好的选择吗?

那应该是-'1234'我会说“不”,因为-运算符将其参数转换为数字无论如何,从来没有必要写x - -y

与加法运算符+一起使用一元+进行转换更为常见,在大多数情况下,写+xNumber(x)也同样明确。所以使用:

x + +y

并保存一些打字。