StringBuilder in JavaScript

July 14, 2011 by Vlad
You know (or at least assume) that each JavaScript interpreter concatenates strings inefficiently if strings or string representations of any object are being joined with the "+" operator. It's fine if you just need to join the first and last names. But you really need a more efficient way to concatenate strings if, for example, you have to serialize large objects into JSON or edit XML on the client. .NET has StringBuilder, Java has StringBuffer. Let's build one in JavaScript.

I think it would be simpler if I would just post the entire StringBuilder object and then explain it, piece by piece.
function StringBuilder()
{
var strings = [];

this.append = function (string)
{
string = verify(string);
if (string.length > 0) strings[strings.length] = string;
};

this.appendLine = function (string)
{
string = verify(string);
if (this.isEmpty())
{
if (string.length > 0) strings[strings.length] = string;
else return;
}
else strings[strings.length] = string.length > 0 ? "\r\n" + string : "\r\n";
};

this.clear = function () { strings = []; };

this.isEmpty = function () { return strings.length == 0; };

this.toString = function () { return strings.join(""); };

var verify = function (string)
{
if (!defined(string)) return "";
if (getType(string) != getType(new String())) return String(string);
return string;
};

var defined = function (el)
{
// Changed per Ryan O'Hara's comment:
return el != null && typeof(el) != "undefined";
};

var getType = function (instance)
{
if (!defined(instance.constructor)) throw Error("Unexpected object type");
var type = String(instance.constructor).match(/function\s+(\w+)/);

return defined(type) ? type[1] : "undefined";
};
};

First, we declare a global array "strings". This array is going to hold all objects that our StringBuilder receives from outside. Then we declare public methods "append", "appendLine", "clear", "isEmpty" and "toString". We also declare several private utility methods. Let me explain the private methods first.

The "defined" method comes straight from CodeEffects' client framework and is used to determine if the object it received is defined or not.

The "getType" method is very important because it allows us to see if the object that we are trying to append to our global string needs to be converted to String object first. It starts by looking if the object has constructor. We cannot do much with objects without constructors, so in that case the method throws an Error. We know that object constructors in JavaScript look like "function String ..." or "function Date ...". Therefore, if constructor is found, the method tries to split its signature, looking for the second item which is always the name of object's type. If such item is still not found, the method returns "undefined" string which ultimately will be caught by the "defined" method.

Method "verify" checks if the object is defined. Then it compares its type to the type of String object. And converts the object into String if they don't match.

The public "append" method verifies the passed object and adds it to the "strings" array.

The "appendLine" does pretty much the same as "append" but it also appends a new line in front of each string if the "strings" array is not empty. Or just the string if it is (we don't need the first line to have a new line char in front of it).

The "clear" method ... well, you know what it does :)

The "isEmpty" method returns a Boolean by checking if the "strings" array is empty or not.

And the "toString" method does the main thing - it joins all items of the "strings" array into one single string and returns the result. It is responcibility of the JavaScript interpreter to implement the "join" method of the Array object in the most efficient way. And they normally do an excellent job. Try concatenating a collection of a million long strings using the "+" operator and this StringBuilder. The difference is quite obvious.

Now let's see how we can use this StringBuilder. Let's build a static HTML page and tell its body to invoke function Loaded when the page is done loading:
<html>
<head>
<title>Test page</title>
<script type="text/javascript">

// Insert the StringBuilder object here

function Loaded()
{
var sb = new StringBuilder();
sb.append("String: ");
sb.append("blah blah");
sb.appendLine("Date: ");
sb.append(new Date());
sb.appendLine("Number: ");
sb.append(17);
alert(sb.toString());
};
</script>
</head>
<body onload="Loaded()">
<p>There is no content here.</p>
</body>
</html>

Copy the StringBuilder object from the first code example into the <script> tag, save this page on your disk and open it in any web browser. Download the page's code from the References section.
JavaScript Next »
Comments:
Name (optional):
Comment (URLs are allowed and must start with http:// or https://; all tags will be encoded):
Remaining character count:
SPAMMER? Comments on this site are not included in page source. The stuff that you might post here WILL NOT be indexed by search engines.