【问题标题】:for loop with break vs find() in JavaScript在 JavaScript 中使用 break 与 find() 的 for 循环
【发布时间】:2018-06-13 18:12:24
【问题描述】:

刚刚看到有人这样写:

let id = 1;
...
let employee = null;

for (const e of employees) {
    if (e.id === id) {
        employee = e;
        break;
    }
}

这似乎是一种过于复杂的写法:

let id = 1;
...
let employee = employees.find(e => e.id === id);

使用带有breakfind() 的循环有什么好处吗?

find() 的幕后实现是什么?

【问题讨论】:

  • 可能是一样的。 Find 是不是更简洁和声明性更强?
  • 只是细微的差别,find 返回 undefined 而不是 null,如果没有找到。
  • 问了两个问题,但我怀疑第一个问题更有趣。至于find()的实现,大概是低级语言中高度优化的循环。

标签: javascript loops find break


【解决方案1】:

性能

.find()for...break 快。

检查this link 以获取测试结果。 for...break.find() 慢 30%


.find()源码可以找到here

.find() 在 IE11 及更低版本等旧版浏览器中不受支持。您需要改用 polyfill。


意见

.find() 由于复杂程度和使用的内部算法而更好。使用for...break,您将始终进行线性搜索,这意味着n * n 重复。数组越大,函数越慢。

【讨论】:

【解决方案2】:

试过这个:

var startTime, endTime;

function start() {
  startTime = new Date();
};

function end() {
  endTime = new Date();
  var timeDiff = endTime - startTime; //in ms
  console.log(timeDiff + " milliseconds");
}

let employees = [];
for (var i = 10000; i > 0; i--){
  let thisEmployee = {
    id: i,
    name: "Person" + i
  }
  employees.push(thisEmployee);
}

let id = 1;
let employee1 = null;
start();
for (const e of employees) {
    if (e.id === id) {
        employee1 = e;
        break;
    }
}
end();
console.log("Method1: ", JSON.stringify(employee1));
start();
let employee2 = employees.find(e => e.id === id);
end();
console.log("Method2: ", JSON.stringify(employee2));

第一种方法要慢得多:

"12 milliseconds"
"Method1: "
"{\"id\":1,\"name\":\"Person1\"}"
"0 milliseconds"
"Method2: "
"{\"id\":1,\"name\":\"Person1\"}"

【讨论】:

【解决方案3】:

我将这两种方法实现为具有相同签名(forBreakMethod(x)findMethod (x))的两个方法,并通过了一个简单的性能测试规范。

(() => {

const test = (DATA_LENGTH = 1000, INDEX = 9, TESTS_COUNT = 10000) => {
  // data initialization
  const employees = [];
  for (let i = 1; i <= DATA_LENGTH; i++){
    employees.push({ id: i });
  }
  
  // methods initialization
  const forBreakMethod = (x) => {
    const length = employees.length;
    for (let i = 0; i < length; i++) {
      if (x === employees.id) {
        return employees[i];
      }
    }
  }
  const findMethod = (x) => {
    return employees.find(item => x === item.id);
  }
  
  // for-break test
  const time1 = performance.now();
  for (let i = 0; i < TESTS_COUNT; i++) {
    forBreakMethod(INDEX);
  }
  const time2 = performance.now();
  console.log(`[for-break] find ${INDEX} from ${DATA_LENGTH}: ${time2 - time1}`);
  
  // find test
  const time3 = performance.now();
  for (let i = 0; i < TESTS_COUNT; i++) {
    findMethod(INDEX);
  }
  const time4 = performance.now();
  console.log(`[Array.find] find ${INDEX} from ${DATA_LENGTH}: ${time4 - time3}`);

  console.log('---------------');
};

test(10, 1, 1000000);
test(10, 5, 1000000);
test(10, 9, 1000000);
console.log('\n');
test(100, 10, 100000);
test(100, 50, 100000);
test(100, 99, 100000);
console.log('\n');
test(1000, 10, 10000);
test(1000, 500, 10000);
test(1000, 999, 10000);
console.log('\n');
test(10000, 10, 10000);
test(10000, 5000, 10000);
test(10000, 9999, 10000);

})();

我看到的一个结论是,如果我们要查找的项目位于数据数组的左侧,则 Array.find 方法具有优势,但是当结果索引向右时,其性能会降低。 for-break 方法似乎更稳定,因为它的性能不依赖于我们要查找的索引,但它的成本很高。

非常粗略,如果我们要遍历数据数组的前半部分,我会说 Array.find 方法可以认为性能更高,否则我会使用 for-break 方法。

PS Chrome、Safari、Firefox,2018 年。

【讨论】:

  • 出色的工作,这是否意味着更大的数组用于 break 更快?
  • @jjwallace 好吧,通常我不会说是,也不会说不。但是这项微小的研究表明,对于具有随机索引的大型数组,找到for-break 方法似乎比Array.find 方法快一点。因为对于右边框,在我的环境中的最后一次测试中,Array.find: 56 + 57
【解决方案4】:

很明显,原生find() 函数比循环算法更快。但是OP问“使用循环有什么好处......?” 有人可能想要循环的一个理论上的原因是他们是否需要在此过程中处理不匹配的元素。

【讨论】:

    【解决方案5】:

    所以我只是尝试了这个:

    const array = [0, 1, 2, 3, 4, 5,];
    
    for (const i of array) {
      console.log(i);
      if (i === 3)
        break;
    }
    
    array.find(i => {
      console.log(i);
      return i === 3;
    });
    

    两者都输出

    0
    1
    2
    3
    

    因此,正如我所期望的那样,他们在找到的第一个答案上都短路了,但至于具体性能,我不能确定一个是否比另一个更好。我想如果不完全相同,性能将具有可比性。
    对我来说突出的一大区别是find 返回值,但 for 循环必须在循环中处理值,否则将其分配给变量以供以后使用。一个小细节,但它可能会使 find 对查看您的代码的其他人更具可读性。

    【讨论】:

      猜你喜欢
      • 2017-02-02
      • 1970-01-01
      • 1970-01-01
      • 2017-06-09
      • 2011-04-28
      • 2019-11-11
      • 2020-07-11
      • 2017-11-02
      • 1970-01-01
      相关资源
      最近更新 更多