【问题标题】:Why is implicit casting is much faster than explicit in JS? Is implicit casting a good practice?为什么隐式转换比 JS 中的显式转换快得多?隐式转换是一个好习惯吗?
【发布时间】:2016-10-05 11:20:03
【问题描述】:

我知道像 String(1234)Number("1234") 这样的类型转换更简洁更好,但我只是尝试对做同样事情的替代方法进行基准测试,特别是 "" + 1234 // -> "1234"- - "1234" // -> 1234

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

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

var then = Date.now(); 
for (var i = 0; i < 100000000; ++i) {
    var a = - - "1234";
}; 
console.log(Date.now() - then);

Number("1234") 用了 2351 毫秒,而- - "1234" 只用了 748 毫秒。

反过来,String(1234) 用了 3701 毫秒,而"" + 1234 只用了 893 毫秒。

差异惊人的巨大。

我的问题是:是什么让显式转换比隐式转换慢得多?我的直觉告诉我应该反过来。

使用隐式转换是一个好习惯吗?尤其是 hacky - - "1234"?有更好的选择吗?

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

【问题讨论】:

  • - - "1234"可以写成+ "1234"
  • 这些不是强制转换,它们是实例化。您尚未展示您的基准测试代码,但运行时可能更擅长处理和优化常量表达式与实例化的数量。
  • @andlrc 如果这样写,它会返回数字。但是如果在像123 + "123" 这样的表达式中,它会返回"123123"。你可以把它写成123 + + "123",但我觉得它和123 - - "123" 很相似
  • @BoltKey——但你永远不会真的这么写,表达式更有可能是1234 - x,在这种情况下,- 运算符将 x 转换为 Number anway (*/ 也是如此)。唯一需要显式转换的是+ 运算符,所以只有1234 + +x 之类的东西。
  • 查看您的代码,这似乎主要是我所怀疑的。 - - "1234" 很早就可以识别为常量表达式。那只是数字 1234。它被创建了一次。您的另一个变体实际上要求实例化无数 Number 对象,然后将其丢弃。

标签: javascript performance type-conversion


【解决方案1】:

如果你不使用常量,如果你使用iinstant 那么结果会完全不同:

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

【讨论】:

  • 很好的解释。 Firefox 非常慢是因为它对常量表达式的优化不好,对吧?
  • @BoltKey 我不得不承认,我只能猜测为什么 Firefox 会这么慢。但至于我的测试——没有常量——Firefox 仍然比 Chromium 慢 10 倍。使用i 而不是常量,大约会慢 15%。
  • @andlrc 你有没有机会在控制台中测试这个?这不会在所有浏览器中执行所有优化。我在 Chrome、Safari 和 Firefox 中测试了所有这些,它们在相似的时间运行,其中 Safari 最快,其次是 FF 和 Chrome。由于这是一个高度人为的合成微基准测试,因此说其中一种方法比另一种方法可靠地快而且浏览器之间的差异也不是特别显着是不明智的。
【解决方案2】:

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

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

是什么让显式转换比隐式转换慢得多?我的直觉告诉我应该反过来。

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

使用隐式转换是一个好习惯吗?尤其是hacky——“1234”?有更好的选择吗?

那应该是-'1234',我会说“不”,因为- 运算符无论如何都会将它的参数转换为数字,永远不需要写x - -y

将一元 + 与加法运算符 + 结合使用进行转换更为常见,并且在大多数情况下,写成 +xNumber(x) 同样清楚。所以使用:

x + +y

并节省一些输入。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-03-16
    • 1970-01-01
    • 1970-01-01
    • 2014-11-15
    • 2011-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多