String concatenation comparisons For some time, JavaScript string concatenation could be optimised by join()ing an array of strings, instead of +ing them together.

Recently, browsers have been optimised to handle strings better, and +ing is back in favour.

The various posts I've read on the subject have cited many jsperf.com tests, which are invariably regular, and nothing much like the dynamic irregularity typically encountered in most web apps that need to concatenate on the fly.

So, I built a new test, the idea of which is to subject each method of concatenation to a relatively equal degree of randomness.

The results show a similar performance difference as other tests of arr.join("") vs. str + str.

Question: Is this jsperf.com test code good jsperf.com test code; is there method in my madness, or am I just mad?

Familiararity with jsperf.com testing is assumed.



"Where a script is concatenating arbitrary numbers of strings dynamically and often, is it 'better' to define a function to handle it, arr.join() inline, or perform simple inline concatenations?"

Preparation code:

Here I aim simply to create a large string from which random substrings can be extracted and stored to global vars for concatenation during the test runs. Also create a couple of functions, one for programmatic concatenation of an arbitrary number of strings using the arr.join("") method, and another for the random selection of the global substrings.

var base = "so many ways to skin a cat",
    c = 0, bl, hbl,
    rand = function( s, e ) {
        return Math.floor( Math.random() * ( e - s ) ) + s;
    },
    concatenateThese = function() {
        return [].slice.call( arguments ).join( "" );
    };
while ( ++c &lt; 10 ) {
    base += base;
}
bl = base.length;
hbl = Math.floor( bl / 2 );
c = 0;
while ( ++c &lt; 100 ) {
    window[ "randStr" + c ] = base.substr( rand( 0, hbl ), rand( hbl, bl ) );
}


My intention is that all the following test snippets are subject to a realistically equal amount of computational randomness where e.g. gluing an identical string to itself for 10000 iterations, can't be itself optimised. Each value is unknowable until runtime.

Test Snippet 1:

This should concatenate 7 randomly selected global strings from those created by the preparation code, by use of the + operator.

var rslt = window[ "randStr" + rand( 0, 100 ) ] +
    window[ "randStr" + rand( 0, 100 ) ] +
    window[ "randStr" + rand( 0, 100 ) ] +
    window[ "randStr" + rand( 0, 100 ) ] +
    window[ "randStr" + rand( 0, 100 ) ] +
    window[ "randStr" + rand( 0, 100 ) ] +
    window[ "randStr" + rand( 0, 100 ) ];


Test Snippet 2:

This should concatenate 7 randomly selected global strings from those created by the preparation code, by use of the join() method.

var rslt = [ window[ "randStr" + rand( 0, 100 ) ],
    window[ "randStr" + rand( 0, 100 ) ],
    window[ "randStr" + rand( 0, 100 ) ],
    window[ "randStr" + rand( 0, 100 ) ],
    window[ "randStr" + rand( 0, 100 ) ],
    window[ "randStr" + rand( 0, 100 ) ],
    window[ "randStr" + rand( 0, 100 ) ] ].join( "" );


Test Snippet 3:

This should concatenate 7 randomly selected global strings from those created by the preparation code, by use of the join() method via a handler function created by the preparation code.

var rslt = concatenateThese( window[ "randStr" + rand( 0, 100 ) ],
    window[ "randStr" + rand( 0, 100 ) ],
    window[ "randStr" + rand( 0, 100 ) ],
    window[ "randStr" + rand( 0, 100 ) ],
    window[ "randStr" + rand( 0, 100 ) ],
    window[ "randStr" + rand( 0, 100 ) ],
    window[ "randStr" + rand( 0, 100 ) ] );
Is this jsperf.com test code good jsperf.com test code; is there method in my madness, or am I just mad?


Probably. This is a micro-optimization whose performance is really negligible in recent browsers. The only browsers I remember choking when it comes to strings were IE8 and older.

With that said, out of all your methods, concatenation with + is an obvious winner, all because it operates solely on strings. The other methods use an array as glue.

Test #2 is at a disadvantage as it has to wrap the strings into an array before they get concatenated by join. Test #3 is in even more disadvantage as you are creating an array twice, first on [] and second on slice.

And even with that, in terms of readability, all three look horrible in the presence of template strings which was designed to improve concatenation and interpolation in strings. It should be present on Firefox, Chrome and Edge as well as transpiler setups. Babel uses the + method when transpiling template strings, so there must be a reason for doing so.



So I have skimmed over the actual test code, and focused more on the approaches. By the way, I believe jsperf is just a front and persistent service that uses Benchmark.js under the hood. So if you're doing any actual testing, best use the library directly and locally.

var base = "so many ways to skin a cat",
  c = 0, bl, hbl,
  rand = function( s, e ) {
    return Math.floor( Math.random() * ( e - s ) ) + s;
  },
  concatenateThese = function() {
    return [].slice.call( arguments ).join( "" );
  };


A lot of vaguely named variables. What's c, bl, hbl, s, e and everything else? Tests are made to verify code. If I can't read the test, how do I know it works? How do I know what it's supposed to do?

rand appears to be a ranged random number generator. Name it as such. concatenateThese... concatenate what exactly? Sure, there's arguments, but the thing about code is that if I cannot know what the code does without having to dig up the source or pull up a debugger, then that's terrible code. 

var base = "so many ways to skin a cat",

/* ton of code between */

while ( ++c &lt; 10 ) {
    base += base;
}


Why are these two pieces of code separate? If I were reading code and the other part was 100 lines or more apart, I would wonder how base was 10 times the size. I'd have to (gasp) dig up the source... again.

By the way, another way of multiplying a string is

Array(10).join('the sentence you want multiplied');


You happen to use window. That's... bad. Nobody wants to pollute the global namespace. Suggesting you store those random strings in an array or object, not on window. While jsperf tests are isolated from each other, your prep code and tests aren't. There's a chance you might introduce something in either code that can infect the other, causing erroneous test results. Sure, you namespaced with randStr, but that doesn't guarantee that you won't mess it up in the long run. Writing tests is tedious, refactoring tests is a nightmare. Best done right always.