JavaScript字符串是不可变的吗? 我需要JavaScript中的“字符串生成器”吗?
JavaScript使用不可变或可变的字符串? 我需要一个“字符串生成器”吗?
他们是不变的。 你不能用类似var myString = "abbdef"; myString[2] = 'c'
来改变字符串中的字符var myString = "abbdef"; myString[2] = 'c'
var myString = "abbdef"; myString[2] = 'c'
。 字符串操作方法,如trim
, slice
返回新的字符串。
但是,我总是听到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.push
和Array.join
- 使用数组索引来避免
Array.push
,然后使用Array.join
- 直串连接
然后,我通过将它们抽象成StringBuilderConcat
, StringBuilderArrayPush
和StringBuilderArrayIndex
创建相同的三个测试。请到那里运行测试,以便我们可以得到一个很好的示例。 请注意,我修正了一个小错误,所以测试的数据被清除了,一旦有足够的性能数据,我将更新表格。 旧数据表转到http://jsperf.com/string-concat-without-sringbuilder/5 。
以下是2013年2月21日的一些数字,如果您不想跟随链接。 每个测试中的数字都在运行/秒( 越高越好 )
| Browser | Index | Push | Concat | SBIndex | SBPush | SBConcat | --------------------------------------------------------------------------- | Chrome 24.0.1312 | 83 | 87 | 702 | 69 | 87 | 165 | | Chrome 25.0.1364 | 43 | 47 | 620 | 42 | 42 | 68 | | Firefox 10.0.10 | 164 | 164 | 533 | 164 | 16 | 421 | | Firefox 19.0 | 70 | 70 | 259 | 70 | 70 | 186 | | Exploder 7.0 | 51 | 33 | 58 | 31 | 37 | 45 | | Exploder 8.0 | 48 | 30 | 58 | 30 | 36 | 36 | | Exploder 9.0 | 87 | 64 | 95 | 61 | 61 | 61 | | Opera 12.14 | 125 | 154 | 66 | 106 | 137 | 63 |
发现
-
如今,所有浏览器都能很好地处理字符串连接。
Array.join
只能帮助Opera -
总的来说,Chrome是最快的,在27.0的时钟速度为1025 ops / sec。 比使用Array.join()快10倍
-
火狐排在第二位,大约550 ops / sec(但20.0似乎已经倒退)。
Array.join
约慢4-5倍。 -
IE使用直接字符串连接速度最快,使用
Array.join
和Array.push
确实很慢。 IE 9使Array.join
不那么慢,所有的SB抽象执行几乎相同的方式(可能是因为方法开销) -
Opera是
Array.join
实际上唯一帮助的,它是字符串连接的2-3倍。 -
创建一个StringBuilder来抽象掉每个浏览器的性能问题不是好事。 方法调用的开销可能是可以接受的,但趋势似乎是浏览器更巧妙地处理字符串连接。 只有当你的目标受众是Opera时才有意义,所以你可以在那里使用Array.join并且在其他地方使用String concatenation(这意味着所有其他的浏览器都会被击中)
希望别人认为这有用
不同的测试案例
由于@RoyTinker认为我的测试是有缺陷的,所以我创建了一个新的例子,它不会通过连接相同的字符串来创建一个大的字符串,而是为每个迭代使用一个不同的字符。 字符串连接仍然看起来更快或者一样快。 让我们来运行这些测试。
我建议大家应该不断思考其他方法来测试这个,感谢Roy的投入。
从犀牛书 :
在JavaScript中,字符串是不可变的对象,这意味着它们中的字符可能不会改变,字符串上的任何操作实际上都会创建新的字符串。 字符串按引用分配,而不是按值分配。 一般情况下,当一个对象被引用赋值时,通过一个引用对对象所做的更改将通过对该对象的所有其他引用而可见。 因为字符串不能被改变,所以你可以有多个对字符串对象的引用,不用担心字符串的值会在你不知道的情况下改变
性能提示:
如果您必须连接大字符串,请将字符串部分放入数组中,并使用Array.Join()
方法获取整个字符串。 连接大量的字符串可以快很多倍。
JavaScript中没有StringBuilder
。
JavaScript字符串确实是不可变的。
Javascript中的字符串是不可改变的
关于你的问题(在你对Ash的回应的评论中)关于ASP.NET Ajax中的StringBuilder的问题,专家似乎不同意这个问题。
Christian Wenz在他的书“ ASP.NET AJAX编程 ”(O'Reilly)中说:“这种方法对内存没有任何可衡量的影响(事实上,实现似乎比标准方法慢)”。
另一方面,Gallo等人在他们的ASP.NET AJAX in Action (Manning)的书中说:“当要连接的字符串数量较大时,字符串生成器成为避免巨大性能下降的基本对象。
我想你会需要做你自己的基准测试,结果也可能会因浏览器而异。 但是,即使它不能提高性能,对于习惯用C#或Java等语言编写StringBuilders的程序员来说,它仍然是“有用的”。
字符串是不可改变的 – 它们不能改变,我们只能制造新的字符串。
例:
var str= "Immutable value"; // it is immutable var other= statement.slice(2, 10); // new string
字符串类型的值是不可变的, 但通过使用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.字符串对象是可变的,但它包含的字符串类型值(基本类型)是不可变的。