【问题标题】:Most efficient way to concatenate strings in JavaScript?在 JavaScript 中连接字符串的最有效方法是什么?
【发布时间】:2013-05-17 19:00:31
【问题描述】:

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

【问题讨论】:

标签: javascript string performance concatenation


【解决方案1】:

似乎基于JSPerf 的基准测试,使用+= 是最快的方法,但不一定适用于所有浏览器。

对于在 DOM 中构建字符串,seems to be better 先将字符串连接起来,然后添加到 DOM,而不是迭代地添加到 dom。不过,您应该对自己的案例进行基准测试。

(感谢@zAlbee 更正)

【讨论】:

  • 查看链接页面。似乎+= 和对数组进行连接几乎没有区别。
  • 似乎将它添加到每个字符串的 DOM 中是 66%(对于 IE9)比创建一个字符串然后将字符串添加到 DOM 更快。
  • 链接页面对两个测试都使用 +=,看不到 .join(),所以这是一个毫无意义的测试,只会将噪音显示为任何“差异”。很好的例子来说明 js 的噪音有多大... dom 比 string 慢,所以要谨慎使用它。
  • 时间只是一个组成部分。对于迭代例程,不知道各种方法对GC有什么影响?
  • JSPerf 链接已失效
【解决方案2】:

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

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

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

这个fixed test 表明在渲染之前一次性创建字符串要快得多。这甚至不是比赛。

(抱歉,这是一个单独的答案,但我还没有足够的代表来评论答案。)

【讨论】:

  • 我认为值得自己做一个答案,因为它包含一个测试和一个结论(虽然测试是基于/启发另一个答案,但应该没问题),无需抱歉。
【解决方案3】:

自从这个问题被回答以来已经三年了,但无论如何我都会提供我的答案:)

实际上,接受的答案并不完全正确。 Jakub 的测试使用硬编码字符串,它允许 JS 引擎优化代码执行(Google 的 V8 在这方面真的很不错!)。 但是,一旦您使用完全随机的字符串 (here is JSPerf),字符串连接就会排在第二位。

【讨论】:

  • 有趣的是,在我的 Windows 机器上使用 Chrome 54 和 Firefox 45,concat 的速度是使用您的版本的其他两个速度的两倍多。 IE 11 的这三个都与其他两个浏览器中的非 concat 一样慢。
  • 版本不同。我想,现在 Chrome 的虚拟机可能包含一些针对这种情况的预优化。我在 Chrome v53 上再次测试,连接现在是最快的解决方案:D 相同的硬件但不同的 Chrome 版本会给出完全不同的结果。
【解决方案4】:

我在 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(""); });

节点中的结果:7.0.10

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

chrome 86.0.4240.198 的结果:

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

【讨论】:

    【解决方案5】:

    您也可以使用template literals 进行字符串连接。我更新了其他海报的JSPerf tests 以包含它。

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

    【讨论】:

    • jsperf.com - "503: SERVICE_UNAVAILABLE".
    【解决方案6】:

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

    perf.link test

    测试代码:

    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)
    

    【讨论】:

    • 请注意,您链接到的 MDN 文档指出:强烈建议使用赋值运算符(+、+=)而不是 concat() 方法
    • @Josh 是的,但我的测试证明这是错误的。要么建议已经过时,不适用于这种情况,要么我的测试是错误的。
    • 在 Chromium 中它运行得更快,但在 Firefox 中它的性能很差。它也有限制——不超过 64000 项。
    • 值得注意的是,.join() 还连接了每个字符串之间的(空)分隔符。因此,它可能比.concat() 慢一点,但也更灵活。如果您需要分隔符,.join() 无疑是赢家。
    【解决方案7】:

    我无法评论其他人的答案(没有足够的代表),所以我会说使用模板文字的MadBreaks' answer 很好,但是如果构建需要与 IE 兼容的网站(Internet资源管理器),因为template literals aren't compatible with IE。因此,在这种情况下,您可以只使用赋值运算符(+、+=)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-21
      • 2016-07-28
      • 1970-01-01
      • 2010-09-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多