为什么一个函数在满数组时比在空数组时工作得更快

Why a function work faster with full array than with empty

我有两个函数实现,它们获取数组的最后一个元素。

function first(array) {
  var length = array ? array.length : 0;
  return length ? array[length - 1] : undefined;
}

function second(array) {
  return array ? array[array.length - 1] : undefined;
}

第二个函数处理完整数组的速度比第一个快,但处理空数组的速度慢。为什么以及如何修复它?

完整数组的基准:http://jsperf.com/lodash-f-last/

空数组基准测试: http://jsperf.com/lodash-f-last/2

在空数组的情况下,它可能是数组查找的成本,因为您的算法在零长度时表现不同,请注意 ? 运算符的控制变量:

function first(array) {
  var length = array ? array.length : 0;
  return length ? array[length - 1] : undefined;
}

returns undefined for [] 来自评估 ?: 构造的右侧,因为 0 评估为 false。

另一方面,

function second(array) {
  return array ? array[array.length - 1] : undefined;
}

returns undefined for [] from evaluating array[-1], because [] evaluates to true.

在完整数组的情况下,第二个算法简单得多。

对我来说,second 函数似乎 使用完整数组 更快,因为您不必执行 var length = array ? array.length : 0; 就像在第一个函数中一样,它为您节省了一个额外的三元条件。

使用 空数组 但是,second 函数 较慢 因为你被迫做一个 arr[-1] (因为空数组在 if 中仍然提供 true )这是一个 getter 函数,在第一个函数中条件是 if (0) 这是假的,你只是 return 未定义。

关于你的第二个问题 - 如何修复它 - 我认为这会成功,因为它会节省你的 getter 功能:

function second(array) {
  return array && array.length ? array[array.length - 1] : undefined;
}

如果你想让你的代码运行得更快,你永远不应该越界读取:V8 deoptimizes 这样做的代码。

在您的 second 函数中,您正是这样做的 - 您读取了边界。而是在阅读之前进行边界检查:

function xlast(array) {
  return (array && array.length > 0) ? array[array.length - 1] 
                                     : undefined;
}