Are JavaScript strings immutable? Do I need a “string builder” in JavaScript?


Does javascript use immutable or mutable strings? Do I need a "string builder"?

They are immutable. You cannot change a character within a string with something like var myString = "abbdef"; myString[2] = 'c'. The string manipulation methods such as trim, slice return new strings.

In the same way, if you have two references to the same string, modifying one doesn't affect the other

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

However, I've always heard what Ash mentioned in his answer (that using Array.join is faster for concatenation) so I wanted to test out the different methods of concatenating strings and abstracting the fastest way into a StringBuilder. I wrote some tests to see if this is true (it isn't!).

This was what I believed would be the fastest way, though I kept thinking that adding a method call may make it slower...

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('');
}

Here are performance speed tests. All three of them create a gigantic string made up of concatenating "Hello diggity dog" one hundred thousand times into an empty string.

I've created three types of tests

  • Using Array.push and Array.join
  • Using Array indexing to avoid Array.push, then using Array.join
  • Straight string concatenation

Then I created the same three tests by abstracting them into StringBuilderConcat, StringBuilderArrayPush and StringBuilderArrayIndex http://jsperf.com/string-concat-without-sringbuilder/5 Please go there and run tests so we can get a nice sample. Note that I fixed a small bug, so the data for the tests got wiped, I will update the table once there's enough performance data. Go to http://jsperf.com/string-concat-without-sringbuilder/5 for the old data table.

Here are some numbers (Latest update in Ma5rch 2018), if you don't want to follow the link. The number on each test is in 1000 operations/second (higher is better)

| 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     | 

Findings

  • Nowadays, all evergreen browsers handle string concatenation well. Array.join only helps IE 11

  • Overall, Opera is fastest, 4 times as fast as Array.join

  • Firefox is second and Array.join is only slightly slower in FF but considerably slower (3x) in Chrome.

  • Chrome is third but string concat is 3 times faster than Array.join

  • Creating a StringBuilder seems to not affect perfomance too much.

Hope somebody else finds this useful

Different Test Case

Since @RoyTinker thought that my test was flawed, I created a new case that doesn't create a big string by concatenating the same string, it uses a different character for each iteration. String concatenation still seemed faster or just as fast. Let's get those tests running.

I suggest everybody should keep thinking of other ways to test this, and feel free to add new links to different test cases below.

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


from the rhino book:

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


Performance tip:

If you have to concatenate large strings, put the string parts into an array and use the Array.Join() method to get the overall string. This can be many times faster for concatenating a large number of strings.

There is no StringBuilder in JavaScript.


Just to clarify for simple minds like mine (from MDN):

Immutables are the objects whose state cannot be changed once the object is created.

String and Numbers are Immutable.

Immutable means that:

You can make a variable name point to a new value, but the previous value is still held in memory. Hence the need for garbage collection.

var immutableString = "Hello";

// In the above code, a new object with string value is created.

immutableString = immutableString + "World";

// We are now appending "World" to the existing value.

This looks like we're mutating the string 'immutableString', but we're not. Instead:

On appending the "immutableString" with a string value, following events occur:

  1. Existing value of "immutableString" is retrieved
  2. "World" is appended to the existing value of "immutableString"
  3. The resultant value is then allocated to a new block of memory
  4. "immutableString" object now points to the newly created memory space
  5. Previously created memory space is now available for garbage collection.

The string type value is immutable, but the String object, which is created by using the String() constructor, is mutable, because it is an object and you can add new properties to it.

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

Meanwhile, although you can add new properties, you can't change the already existing properties

A screenshot of a test in Chrome console

In conclusion, 1. all string type value (primitive type) is immutable. 2. The String object is mutable, but the string type value (primitive type) it contains is immutable.


Strings are immutable – they cannot change, we can only ever make new strings.

Example:

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

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

Regarding your question (in your comment to Ash's response) about the StringBuilder in ASP.NET Ajax the experts seem to disagree on this one.

Christian Wenz says in his book Programming ASP.NET AJAX (O'Reilly) that "this approach does not have any measurable effect on memory (in fact, the implementation seems to be a tick slower than the standard approach)."

On the other hand Gallo et al say in their book ASP.NET AJAX in Action (Manning) that "When the number of strings to concatenate is larger, the string builder becomes an essential object to avoid huge performance drops."

I guess you'd need to do your own benchmarking and results might differ between browsers, too. However, even if it doesn't improve performance it might still be considered "useful" for programmers who are used to coding with StringBuilders in languages like C# or Java.


It's a late post, but I didn't find a good book quote among the answers.

Here's a definite except from a reliable book:

Strings are immutable in ECMAScript, meaning that once they are created, their values cannot change. To change the string held by a variable, the original string must be destroyed and the variable filled with another string containing a new value... —Professional JavaScript for Web Developers, 3rd Ed., p.43

Now, the answer which quotes Rhino book's excerpt is right about string immutability but wrong saying "Strings are assigned by reference, not by value." (probably they originally meant to put the words an opposite way).

The "reference/value" misconception is clarified in the "Professional JavaScript", chapter named "Primitive and Reference values":

The five primitive types...[are]: Undefined, Null, Boolean, Number, and String. These variables are said to be accessed by value, because you are manipulating the actual value stored in the variable. —Professional JavaScript for Web Developers, 3rd Ed., p.85

that's opposed to objects:

When you manipulate an object, you’re really working on a reference to that object rather than the actual object itself. For this reason, such values are said to be accessed by reference.—Professional JavaScript for Web Developers, 3rd Ed., p.85


JavaScript strings are indeed immutable.


Strings in Javascript are immutable