Earlier today, out of sheer curiosity, I wanted to find out the quickest method of duplicating an array in JavaScript. The different methods I tested included:

  • Calling the array’s slice method, passing 0:
    originalArray.slice(0);
  • Creating a new array, applying the entire original array:
    Array.apply(Array, arrayToDuplicate);
    // Shorter version of:
    // (new Array()).apply( new Array(), originalArray);
  • Looping through the original array, copying one by one:
    var duplicate = [];
    for (var i = 0, len = originalArray.length; i < len; i++) {
        duplicate[duplicate.length] = originalArray[i];
    }

Note that none of the above methods perform a “deep copy” so any “pass-by-reference” values within the original array will not be copied, just referenced from within the duplicate array. Also note that, in this post, when I refer to a “method” I may just be referring to a regular function.

To perform this test I constructed a basic speed-testing class, and that is what I’m sharing with you today:

function SpeedComparison(testData, accuracy, methods) {
    if ( ! (this instanceof arguments.callee) ) { return; }
    this.accuracy = accuracy || 1000;
    this.methods = methods || {};
    this.testData = testData;
    this.results = {};
}
 
SpeedComparison.prototype = {
    addMethod : function(name, method) {
        this.methods[name] = method;
        return this;
    },
    removeMethod : function(name) {
        delete this.methods[name];
        return this;
    },
    begin : function() {
        iterateMethods : for (var method in this.methods) {
            var sTime = +new Date();
            for (var i = 0, a = this.accuracy; i < a; i++) {
                if (this.methods[method](this.testData) === false) {
                    this.results[method] = 'Failed';
                    continue iterateMethods;
                }
            }
            var fTime = +new Date();
            this.results[method] = fTime - sTime;
        }
    }
};

The SpeedComparison constructor accepts three parameters:

  • testData – whatever you pass here is passed to each method you specify (each method to be compared).
  • accuracy – this is the number of times the different methods will be compared, i.e. how many times each method is run.
  • methods – an object containing all of the methods to be compared.

All parameters are optional and can be added/changed later via their respective properties.

An example

Here’s how I tested the different methods of duplicating an array (discussed earlier):

var testArray = ['a', 'very', 'big', 'array', 'etc.'];
var arrayCopyTest = new SpeedComparison(testArray, 5000);
 
// Add each method to be tested:
arrayCopyTest.methods = {
    'Slice' : function(testData) {
        testData.slice(0);
    },
    'New Array' : function(testData) {
        Array.apply(Array, testData);
    },
    'Loop' : function(testData) {
        var ret = [];
        for (var i = 0, len = testData.length; i < len; i++) {
            ret[ret.length] = testData[i];
        }
    }
};
 
arrayCopyTest.begin();
 
console.log (arrayCopyTest.results);
 
// "arrayCopyTest.results" shows all methods' times - lower is better.

For those interested, here are the results from that test:

“Slice” (ms) “New Array” (ms) “Loop” (ms)
Firefox 3 15 24 103
IE 7 250 219 484
Chrome 23 7 15
Safari 4 25 9 23

Interestingly, in all browsers other than Firefox, the 2nd method performs the best:

Array.apply(Array, originalArray);

The speedComparison class is useful for quick n’ dirty speed checks like this.

Right now, it only gives you the times (in milliseconds), but the results could easily be extended via the prototype. I know that more sophisticated means exist to perform such tests; I just needed something simple and functional to conduct a few small speed comparisons.

Thanks for reading! Please share your thoughts with me on Twitter. Have a great day!