在JavaScript中连接字符串的最有效方法?

ome*_*ega 147 javascript string performance concatenation

在JavaScript中,我有一个循环,有许多迭代,并在每次迭代中,我创建一个包含许多+=运算符的巨大字符串.有没有更有效的方法来创建一个字符串?我正在考虑创建一个动态数组,我不断添加字符串,然后进行连接.任何人都可以解释并举例说明最快的方法吗?

Jak*_*mpl 129

似乎基于JSPerf的基准测试,使用+=是最快的方法,但不一定在每个浏览器中.

为了在DOM中构建字符串,最好先连接字符串然后再添加到DOM,而不是迭代地将它添加到dom中.你应该对自己的情况进行基准测试.

(谢谢@zAlbee纠正)

  • JSPerf 链接已失效 (4认同)
  • JSPerf 链接的网络存档版本:https://web.archive.org/web/20181117202141/jsperf.com/join-concat/2 (4认同)

zAl*_*bee 67

我对连接本身没有评论,但我想指出@Jakub Hampl的建议:

为了在DOM中构建字符串,在某些情况下,迭代地添加到DOM可能会更好,而不是一次添加一个巨大的字符串.

这是错误的,因为它是基于一个有缺陷的测试.该测试从未实际附加到DOM中.

这个固定的测试显示在渲染之前一次创建字符串的速度要快得多.这甚至不是一场比赛.

(对不起,这是一个单独的答案,但我还没有足够的代表对答案发表评论.)

  • 我认为它本身就是一个答案,因为它包含一个测试和一个结论(尽管测试基于/启发了另一个答案,应该没问题),不需要抱歉. (3认同)

Vol*_*kyy 13

自这个问题得到回答三年后,我仍然会提供我的答案:)

实际上,接受的答案并不完全正确.Jakub的测试使用硬编码字符串,允许JS引擎优化代码执行(谷歌的V8在这方面非常好!).但是只要你使用完全随机的字符串(这里是JSPerf),字符串连接就会在第二位.

  • 各个版本不同。我猜想,现在Chrome的VM可能针对这种情况进行了一些预优化。我在Chrome v53上再次进行了测试,现在串联是最快的解决方案:D相同的硬件,但不同的Chrome版本给出了完全不同的结果。 (2认同)

gra*_*aup 7

我想知道为什么String.prototype.concat没有得到任何爱。在我的测试中(假设您已经有一个字符串数组),它优于所有其他方法。

性能链路测试

测试代码:

const numStrings = 100;
const strings = [...new Array(numStrings)].map(() => Math.random().toString(36).substring(6));

const concatReduce = (strs) => strs.reduce((a, b) => a + b);

const concatLoop = (strs) => {
  let result = ''
  for (let i = 0; i < strings.length; i++) {
    result += strings[i];
  }
  return result;
}

// Case 1: 52,570 ops/s
concatLoop(strings);

// Case 2: 96,450 ops/s
concatReduce(strings)

// Case 3: 138,020 ops/s
strings.join('')

// Case 4: 169,520 ops/s
''.concat(...strings)
Run Code Online (Sandbox Code Playgroud)

  • 请注意,您链接到的 MDN 文档指出: 强烈建议使用赋值运算符 (+, +=) 而不是 concat() 方法 (2认同)
  • @Josh 是的,但我的测试证明这是错误的。要么该建议已经过时,不适用于这种情况,要么我的测试是错误的。 (2认同)
  • 在 Chromium 中它运行得更快,但在 Firefox 中它的性能很糟糕。它也有限制——不超过 64000 个项目。 (2认同)

Mad*_*aks 5

您也可以使用模板文字进行字符串连接。我更新了其他发布者的JSPerf测试以包括其中。

for (var res = '', i = 0; i < data.length; i++) {
  res = `${res}${data[i]}`;
}
Run Code Online (Sandbox Code Playgroud)

  • jsperf.com - *“503:服务不可用”*。 (3认同)

Pet*_*esz 5

我在 node 和 chrome 中都做了一个快速测试,发现在这两种情况下+=都更快:

var profile = func => { 
    var start = new Date();
    for (var i = 0; i < 10000000; i++) func('test');
    console.log(new Date() - start);
}
profile(x => "testtesttesttesttest");
profile(x => `${x}${x}${x}${x}${x}`);
profile(x => x + x + x + x + x );
profile(x => { var s = x; s += x; s += x; s += x; s += x; return s; });
profile(x => [x, x, x, x, x].join(""));
profile(x => { var a = [x]; a.push(x); a.push(x); a.push(x); a.push(x); return a.join(""); });
Run Code Online (Sandbox Code Playgroud)

结果节点:7.0.10

  • 作业:8
  • 模板文字:524
  • 加:382
  • 加等于:379
  • 数组连接:1476
  • 数组推送连接:1651

chrome 86.0.4240.198 的结果:

  • 作业:6
  • 模板文字:531
  • 加:406
  • 加等于:403
  • 数组连接:1552
  • 数组推送连接:1813

  • 刚玩过这个。似乎垃圾收集在这里发挥了作用,因为无论您首先选择哪个测试,第一个测试都享有巨大的优势。 (3认同)