JavaScript字符串是不可变的吗?我需要JavaScript中的“字符串构建器”吗?

时间:2008-09-09 03:44:54

标签: javascript string

javascript是否使用不可变或可变的字符串?我需要一个“字符串构建器”吗?

10 个答案:

答案 0 :(得分:272)

他们是不可改变的。您无法使用var myString = "abbdef"; myString[2] = 'c'之类的内容更改字符串中的字符。 trimslice等字符串操作方法会返回新字符串。

同样,如果您对同一个字符串有两个引用,则修改一个字符串不会影响另一个

let a = b = "hello";
a = a + " world";
// b is not affected

但是,我总是听到Ash在他的回答中提到的内容(使用Array.join更快地进行连接)所以我想测试连接字符串的不同方法并将最快的方法抽象到StringBuilder中。我写了一些测试,看看这是否属实(不是!)。

这是我认为最快的方式,但我一直认为添加方法调用可能会让它变慢......

function StringBuilder() {
    this._array = [];
    this._index = 0;
}

StringBuilder.prototype.append = function (str) {
    this._array[this._index] = str;
    this._index++;
}

StringBuilder.prototype.toString = function () {
    return this._array.join('');
}

以下是性能速度测试。他们三个都创建了一个巨大的字符串,由一串空的字符串连接"Hello diggity dog"十万次组成。

我创建了三种类型的测试

  • 使用Array.pushArray.join
  • 使用数组索引来避免Array.push,然后使用Array.join
  • 直字符串连接

然后我通过将它们抽象为StringBuilderConcatStringBuilderArrayPushStringBuilderArrayIndex http://jsperf.com/string-concat-without-sringbuilder/5来创建相同的三个测试。请到那里运行测试,这样我们就可以得到一个很好的样本。请注意,我修复了一个小错误,因此测试数据被擦除,一旦有足够的性能数据,我将更新表。转到http://jsperf.com/string-concat-without-sringbuilder/5获取旧数据表。

以下是一些数字(Ma5rch 2018中的最新更新),如果您不想关注该链接。每项测试的数量为1000次/秒(越高越好

| Browser          | Index | Push | Concat | SBIndex | SBPush | SBConcat |
---------------------------------------------------------------------------
| Chrome 71.0.3578 | 988   | 1006 | 2902   | 963     | 1008   | 2902     |
| Firefox 65       | 1979  | 1902 | 2197   | 1917    | 1873   | 1953     |
| Edge             | 593   | 373  | 952    | 361     | 415    | 444      |
| Exploder 11      | 655   | 532  | 761    | 537     | 567    | 387      |
| Opera 58.0.3135  | 1135  | 1200 | 4357   | 1137    | 1188   | 4294     | 

<强>首饰

  • 如今,所有常绿浏览器都能很好地处理字符串连接。 Array.join仅帮助IE 11

  • 总体而言,Opera速度最快,是Array.join

  • 的4倍
  • Firefox排名第二,Array.join仅在FF中略慢,但在Chrome中速度相当慢(3x)。

  • Chrome排名第三,但字符串concat比Array.join快3倍

  • 创建StringBuilder似乎不会影响性能。

希望别人找到这个有用的

不同的测试用例

由于@RoyTinker认为我的测试有缺陷,我创建了一个新的案例,它不会通过连接相同的字符串来创建一个大字符串,它为每次迭代使用不同的字符。字符串连接似乎仍然更快或更快。让我们让这些测试运行起来。

我建议每个人都应该继续考虑其他测试方法,并随时为下面的不同测试用例添加新的链接。

http://jsperf.com/string-concat-without-sringbuilder/7

答案 1 :(得分:43)

来自rhino book

  

在JavaScript中,字符串是不可变对象,这意味着   其中的字符可能无法更改,也不能进行任何操作   字符串实际上创建新字符串字符串由。分配   参考,而不是价值。通常,当分配对象时   引用,通过一个引用对对象进行的更改将是   通过对象的所有其他引用可见。因为字符串   但是,您可以对a进行多次引用   字符串对象并不担心字符串值会在没有的情况下发生变化   你知道吗

答案 2 :(得分:20)

效果提示:

如果必须连接大字符串,请将字符串部分放入数组中,并使用Array.Join()方法获取整个字符串。对于连接大量字符串,这可以快许多倍。

JavaScript中没有StringBuilder

答案 3 :(得分:2)

字符串是不可变的 - 它们无法更改,我们只能创建新的字符串。

示例:

git branch --contains <acommit>

答案 4 :(得分:2)

字符串类型值是不可变的,但是 String对象(使用String()构造函数创建)是可变的,因为它是一个对象,您可以向其添加新属性。

> var str = new String("test")
undefined
> str
[String: 'test']
> str.newProp = "some value"
'some value'
> str
{ [String: 'test'] newProp: 'some value' }

同时,虽然您可以添加新属性,但无法更改现有属性

A screenshot of a test in Chrome console

总之, 1.所有字符串类型值(基本类型)都是不可变的。 2. String对象是可变的,但它包含的字符串类型值(基本类型)是不可变的。

答案 5 :(得分:2)

只需要澄清像我这样的简单思想(来自MDN):

  

不可变对象是对象一旦创建便无法更改状态的对象。

     

字符串和数字是不可变的。

不可变表示:

  

您可以使变量名指向一个新值,但先前的值仍保留在内存中。因此需要进行垃圾收集。

     

var immutableString = "Hello";

     

//在上面的代码中,创建了一个带有字符串值的新对象。

     

immutableString = immutableString + "World";

     

//我们现在将“世界”附加到现有值上。

这看起来像我们正在对字符串'immutableString'进行突变,但事实并非如此。相反:

  

在将“ immutableString”附加到字符串值后,会发生以下事件:

     
      
  1. 检索“ immutableString”的现有值
  2.   
  3. “世界”被附加到“ immutableString”的现有值上
  4.   
  5. 然后将结果值分配给新的内存块
  6.   
  7. “ immutableString”对象现在指向新创建的内存空间
  8.   
  9. 以前创建的内存空间现在可用于垃圾回收。
  10.   

答案 6 :(得分:1)

关于你在ASP.NET Ajax中关于StringBuilder的问题(在您对Ash的回复的评论中),专家似乎对此不一致。

Christian Wenz在他的书“编程ASP.NET AJAX ”(O'Reilly)中说“这种方法对内存没有任何可测量的影响(实际上,实现似乎更慢了)比标准方法。“

另一方面,Gallo等人在他们的书 ASP.NET AJAX in Action (Manning)中说“当连接的字符串数量越大时,字符串构建器就成为了一个必不可少的对象。避免巨大的性能下降。“

我猜您需要进行自己的基准测试,结果也可能因浏览器而异。但是,即使它没有提高性能,对于那些习惯使用C#或Java等语言编写StringBuilders的程序员来说,它仍然可能被认为是“有用的”。

答案 7 :(得分:1)

这是一篇较晚的文章,但我在答案中找不到合适的书名。

除了可靠的书之外,这是肯定的:

  

字符串在ECMAScript中是不可变的,这意味着一旦创建它们,它们的值就无法更改。要更改变量保存的字符串,必须销毁原始字符串,并用另一个包含新值的字符串填充该变量...   -适用于Web开发人员的专业JavaScript,第3版,第43页

现在,引用Rhino书摘录的答案是关于字符串不变性的,但是说“字符串是通过引用而不是值分配的”是错误的。 (可能他们最初打算用相反的方式表示这些词)。

在“专业JavaScript”的“原始和参考值”一章中澄清了“参考/值”的误解:

  

五种基本类型... [是]:未定义,空,布尔值,数字和字符串。据说这些变量是按值访问的,因为您正在操纵存储在变量中的实际值。   -适用于Web开发人员的专业JavaScript,第3版,第85页

与对象相反的

  

操作对象时,您实际上是在对该对象进行引用,而不是实际对象本身。因此,据说可以通过引用访问这些值。-Web开发人员的专业JavaScript,第3版,第85页

答案 8 :(得分:0)

JavaScript字符串确实是不可变的。

答案 9 :(得分:-2)

Javascript中的字符串是不可变的