javascript使用不可变字符串还是可变字符串?我需要一个“字符串生成器”吗?
当前回答
Javascript中的字符串是不可变的
其他回答
来自犀牛的书:
In JavaScript, strings are immutable objects, which means that the characters within them may not be changed and that any operations on strings actually create new strings. Strings are assigned by reference, not by value. In general, when an object is assigned by reference, a change made to the object through one reference will be visible through all other references to the object. Because strings cannot be changed, however, you can have multiple references to a string object and not worry that the string value will change without your knowing it
它们是不可变的。你不能用像var myString = "abbdef"这样的方法来改变字符串中的字符;myString[2] = 'c'。字符串操作方法,如修剪,切片返回新字符串。
同样地,如果对同一个字符串有两个引用,修改其中一个不会影响另一个
let a = b = "hello";
a = a + " world";
// b is not affected
然而,我总是听到Ash在他的回答中提到的(使用Array。所以我想测试连接字符串的不同方法,并将最快的方法抽象到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('');
}
这里是性能速度测试。这三个都创造了一个巨大的字符串,由“你好,diggity dog”10万次连接到一个空字符串组成。
我创建了三种类型的测试
使用数组。push和Array.join 使用数组索引来避免数组。push,然后使用Array.join 直串连接
然后我通过将它们抽象为StringBuilderConcat, StringBuilderArrayPush和StringBuilderArrayIndex 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 |
发现
现在,所有的常青树浏览器都能很好地处理字符串连接。数组中。join只支持IE 11 总的来说,Opera是最快的,是Array.join的4倍 其次是Firefox和Array。连接只是稍微慢在FF但相当慢(3倍)在Chrome。 Chrome排名第三,但string concat比Array.join快3倍 创建一个StringBuilder似乎对性能影响不大。
希望其他人会觉得这个有用
不同的测试用例
因为@RoyTinker认为我的测试是有缺陷的,我创建了一个新的情况下,不创建一个大字符串连接相同的字符串,它使用不同的字符为每次迭代。字符串连接似乎还是更快,或者一样快。让我们进行测试
我建议每个人都应该继续考虑其他测试方法,并在下面添加到不同测试用例的新链接。
http://jsperf.com/string-concat-without-sringbuilder/7
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. String对象是可变的,但它包含的字符串类型值(基本类型)是不可变的。
这是一个很晚的帖子,但我没有在答案中找到一个好的书的引用。
这是一本可靠的书中明确的注释:
字符串在ECMAScript中是不可变的,这意味着一旦创建了字符串,它们的值就不能改变。要改变由变量保存的字符串,必须销毁原始字符串,并用另一个包含新值的字符串填充变量… -面向Web开发人员的专业JavaScript,第3版,第43页
现在,引用Rhino书摘录的答案是正确的关于字符串不可变性,但错误的说“字符串是通过引用分配的,而不是通过值。”(可能他们最初的意思是反其道而行之)。
“引用/值”的误解在“专业JavaScript”的“原语和参考值”一章中得到了澄清:
五种原始类型……[是]:未定义,空,布尔,数字和字符串。这些变量被称为通过值访问,因为您正在操作存储在变量中的实际值。 -面向Web开发者的专业JavaScript,第3版,第85页
这是与对象相对的:
当您操作一个对象时,实际上是在处理对该对象的引用,而不是实际的对象本身。因此,这样的值被称为通过引用访问。-面向Web开发者的专业JavaScript,第3版,第85页
JavaScript字符串确实是不可变的。