答案在于虚拟机可以对“热函数”进行启发式检测,即执行数百甚至数千次的代码。如果函数的执行计数超过预定限制,VM 优化器可能会选取该代码位并尝试根据传递给函数的参数编译优化版本。在这种情况下,它假定您的函数将始终以相同的方式调用type参数(不一定是same对象)。
其原因在此有详细记录v8特定指南文档 https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#some-v8-background其中解释了整数与一般数字优化。假设你有:
function add(a, b) { return a + b; }
...并且您总是使用整数调用此函数,可以通过编译一个在 CPU 上执行整数求和的函数来优化此方法,该函数速度很快。如果在优化后您向其提供非整数值,则虚拟机将取消优化该函数并回退到未优化的版本,因为它无法对非整数执行整数求和,并且该函数将返回错误的结果。
在指定重载单态方法的语言中,您可以通过简单地编译具有不同参数签名的同一方法名称的多个版本来解决此问题,然后对其进行优化。这意味着您调用不同的优化方法,因为使用不同类型的参数需要您使用不同的重载方法,因此不存在您使用哪种方法的问题。
您可能认为可以在虚拟机中保留优化函数的多个副本,并检查类型以确定要使用哪个优化的编译函数。理论上,如果方法调用之前的类型检查是免费的或非常便宜的话,那么这是可行的。在实践中,情况通常并非如此,您可能希望根据实际代码进行平衡,以确定最佳权衡阈值。
这里有一个更通用的解释,特别是 v8 的优化编译器(来自 Google I/O 2012):
https://youtu.be/UJPdhx5zTaw?t=26m26s https://youtu.be/UJPdhx5zTaw?t=26m26s
简而言之:一遍又一遍地调用相同类型的函数在 JIT 编译器中进行了优化,因此速度更快。