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

2020/10/11 13:21 · javascript ·  · 0评论

JavaScript是否使用不可变或可变的字符串?我需要一个“字符串生成器”吗?

他们是一成不变的。您不能使用诸如此类来更改字符串中的字符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中则慢得多(3倍)。

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

  • 创建一个StringBuilder似乎不会对性能产生太大影响。

希望其他人觉得这有用

不同的测试用例

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

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

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

犀牛书中

在JavaScript中,字符串是不可变的对象,这意味着它们中的字符可能不会更改,并且对字符串的任何操作实际上都会创建新的字符串。字符串是通过引用而不是值来分配的。通常,当一个对象通过引用分配时,通过一个引用对该对象所做的更改将通过对该对象的所有其他引用可见。但是,由于不能更改字符串,因此可以有多个对字符串对象的引用,不必担心字符串值会在不知道的情况下发生变化

性能提示:

如果必须连接较大的字符串,请将字符串部分放入数组中,然后使用该Array.Join()方法获取整个字符串。连接大量字符串的速度可能快许多倍。

StringBuilderJavaScript中没有

只是为了澄清像我这样的简单想法(来自MDN):

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

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

不可变意味着:

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

var immutableString = "Hello";

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

immutableString = immutableString + "World";

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

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

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

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

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

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

同时,尽管可以添加新属性,但是不能更改现有属性

Chrome控制台中的测试屏幕截图

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

字符串是不可变的-它们不能更改,我们只能制造新的字符串。

例:

var str= "Immutable value"; // it is immutable

var other= statement.slice(2, 10); // new string

关于您在ASP.NET Ajax中关于StringBuilder的问题(在对Ash的回应的评论中),专家似乎对此表示不同意见。

克里斯蒂安·温兹(Christian Wenz)在他的《Programming ASP.NET AJAX(O'Reilly)》一书中说:“这种方法对内存没有任何可测量的影响(实际上,该实现似乎比标准方法要慢一点)。

另一方面,盖洛(Gallo)等人在他们的《ASP.NET AJAX实战》(曼宁)一书中说:“当要连接的字符串数量较大时,字符串构建器将成为避免性能大幅下降的重要对象。”

我猜您需要进行自己的基准测试,并且浏览器之间的结果可能也会有所不同。但是,即使它不能提高性能,对于习惯使用C#或Java之类的StringBuilders进行编码的程序员来说,它仍然可能被认为“有用”。

这是一个较晚的帖子,但是我在答案中找不到很好的书名。

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

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

现在,引用Rhino书摘录的答案是关于字符串不变性的,但是说“字符串是通过引用而不是值分配的”是错误的。(可能原本是要相反地使用这些词)。

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

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

对象相反

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

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

Javascript中的字符串是不可变的

本文地址:http://javascript.askforanswer.com/javascriptzifuchuanshibukebiandemawoxuyaojavascriptzhongdezifuchuanshengchengqima.html
文章标签: ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!