为什么字符串串联比数组连接更快?

今天,我读了这个关于字符串串联速度的帖子。

令人惊讶的是,字符串串联是赢家:

http://jsben.ch/#/OJ3vo

结果与我的想法相反。此外,有很多关于此的文章对此进行了相反的解释。

我可以猜测浏览器已针对最新版本进行了优化,但是它们是如何做到这一点的呢?我们能说在连接字符串时使用更好吗?concat+


更新

因此,在现代浏览器中,字符串串联经过优化,因此使用符号比使用符号更快,当您想要连接字符串时。+join

但是@Arthur指出,如果您实际上想要用分隔符连接字符串,则速度更快。join


更新 - 2020
Chrome:数组几乎是字符串连接 请参阅:https://stackoverflow.com/a/54970240/984471join2 times faster+

请注意:

  • 阵列更好,如果你有joinlarge strings
  • 如果我们需要在最终输出中生成,最好使用字符串concat,否则使用数组将需要在最后进行几次数组到字符串的转换,这是性能过载。several small strings+


答案 1

浏览器字符串优化已更改字符串串联图片。

Firefox是第一个优化字符串串联的浏览器。从 1.0 版开始,数组技术实际上比在所有情况下使用 plus 运算符都要慢。其他浏览器也优化了字符串串联,因此Safari,Opera,Chrome和Internet Explorer 8使用plus运算符也显示出更好的性能。版本 8 之前的 Internet Explorer 没有这样的优化,因此数组技术总是比 plus 运算符快。

编写高效的 JavaScript:第 7 章 – 更快的网站

V8 javascript引擎(在Google Chrome中使用)使用此代码进行字符串串联:

// ECMA-262, section 15.5.4.6
function StringConcat() {
  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
    throw MakeTypeError("called_on_null_or_undefined", ["String.prototype.concat"]);
  }
  var len = %_ArgumentsLength();
  var this_as_string = TO_STRING_INLINE(this);
  if (len === 1) {
    return this_as_string + %_Arguments(0);
  }
  var parts = new InternalArray(len + 1);
  parts[0] = this_as_string;
  for (var i = 0; i < len; i++) {
    var part = %_Arguments(i);
    parts[i + 1] = TO_STRING_INLINE(part);
  }
  return %StringBuilderConcat(parts, len + 1, "");
}

因此,在内部,他们通过创建一个内部数组(变量)来优化它,然后将其填充。StringBuilderConcat 函数与这些部分一起调用。它很快,因为StringBuilderConcat函数是一些经过高度优化C++代码。此处引用太长,但在 runtime.cc 文件中搜索以查看代码。partsRUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat)


答案 2

Firefox的速度很快,因为它使用了一种叫做绳索的东西(Ropes:Strings的替代品)。绳子基本上只是一个DAG,其中每个节点都是一个字符串。

例如,如果您这样做,新创建的对象将如下所示。当然,这并不完全是这在内存中的样子,因为你仍然需要有一个字符串类型,长度和其他字段。a = 'abc'.concat('def')

a = {
 nodeA: 'abc',
 nodeB: 'def'
}

b = a.concat('123')

b = {
  nodeA: a, /* {
             nodeA: 'abc',
             nodeB: 'def'
          } */
  nodeB: '123'
}           

因此,在最简单的情况下,VM 几乎不需要执行任何工作。唯一的问题是,这会稍微减慢对结果字符串的其他操作。当然,这当然也减少了内存开销。

另一方面,通常只是分配内存来将新字符串平放在内存中。(也许这应该优化)['abc', 'def'].join('')