Javascript:为什么字符串相等对于较长的字符串需要更长的时间?

Javascript: Why does equality of strings take longer for longer strings?

提问人:user7858768 提问时间:9/21/2021 更新时间:9/21/2021 访问量:144

问:

在下面的代码中,将创建长度相等的 1Mil 字符串。 然后,它们被循环以查找匹配的字符串。 第一次运行的字符串长度是第二次运行的 3 倍。

预期的结果是,对不同长度的字符串进行相等比较所需的时间不会因“字符串实习”而改变。但是,结果显示,长度为 3 倍的字符串大约需要 3 次才能进行相等性检查。为什么?

import { v4 as uuidv4 } from 'uuid';

export const uuid = () => {
  return uuidv4();
};

function createSingleId(howManyUuidsInOneId1: number) {
  let id = '';
  for (let j = 0; j < howManyUuidsInOneId1; j++) {
    id += uuid();
  }
  return id;
}

function generate(howManyIds: number, howManyUuidsInOneId: number) {
  const ids = [];
  for (let i = 0; i < howManyIds; i++) {
    ids.push(createSingleId(howManyUuidsInOneId));
  }
  return ids;
}

const main = (howManyIds: number, howManyUuidsInOneId:number) => {

  const ids = generate(howManyIds, howManyUuidsInOneId);

  const toFind = createSingleId(howManyUuidsInOneId);

  console.log(`Sample id being compared: '${toFind}'`);

  const before = new Date().getTime();

  ids.filter(id => id === toFind);

  console.log(`Took '${new Date().getTime() - before}ms' to loop through and equal compare '${howManyIds}' when stacked '${howManyUuidsInOneId}' in single id`);
};

main(1000000, 3);
main(1000000, 1);

输出:

Sample id being compared: 'dc03bf00-6f2a-48d9-b3ca-b6ac45782c5cefaa92c0-9372-4f47-bcec-f9fbb41d4625e0c5c278-b574-4a9f-a77e-110cbc6bf601'
Took '64ms' to loop through and equal compare '1000000' when stacked '3' in single id
Sample id being compared: '07e693ce-49a1-4cc6-90e1-0bd99629123b'
Took '19ms' to loop through and equal compare '1000000' when stacked '1' in single id
> node --version
v15.14.0
JavaScript TypeScript 等式 字符串实习

评论

5赞 deceze 9/21/2021
它确实需要逐个字符地比较字符串,而更长的字符串需要更长的时间......?!实习仅意味着内存中不会有字符串的多个副本。引擎可能很聪明,并意识到它正在尝试比较相同的内存位置,从而完全跳过它,但显然它没有这样做,和/或字符串没有被隔离(为什么你认为它们应该被隔离?

答:

4赞 Bergi 9/21/2021 #1

预期的结果是,对不同长度的字符串进行相等比较所需的时间不会因“字符串实习”而改变。

不,字符串实习仅意味着对于某些字符串,您知道它们是相同的,因为它们存储在相同的位置,例如,对于从相同字符串文字创建的字符串值。但并不是所有的字符串(尤其是不是动态创建的字符串)都会被隔离,并且具有不同的内存地址并不能说明字符串的内容。如果内存位置检查失败,您仍然需要像往常一样比较字符串内容

一些例子来证明这一点:

function generateString(len) {
  let x = "";
  for (let i=0; i<len; i++) x+= String.fromCharCode(64+i%64);
  return x;
}
function time(callback, desc) {
  const before = performance.now();
  const res = callback();
  console.log(`Took ${performance.now()-before}ms to ${desc}`);
  return res;
}

const strLen = 5000000;
const a = generateString(strLen);
const b = generateString(strLen);
console.assert(a === b);
const str = a;
time(() => str === a, 'compare a with itself');
time(() => str === b, 'compare a with b');

a并且具有相同的内容,但(在内存中)是不同的字符串对象,因为它们是在不同的调用中累积的。 引用与这样做相同的值。bgenerateStringstra

评论

0赞 user7858768 9/21/2021
说得很有道理。出于某种原因,我认为所有字符串都是动态的。