Infinite Ways to Detect Array in JavaScript

JavaScript (ECMA script in general) is a miraculous language. It allows us to prove that coding is creativity. One reason for that is the numerous ways a single objective can be coded. For instance, checking whether a variable is an Array, can be done in four different ways. And probably more!

Some months back I had come across this Quora article: What’s the best way to tell the different between an Array and other kinds of objects in JavaScript? There were already five different methods available there from Tom, John, Rick, Ken and Eric. And even I was surprised that I could add one more! I would take some time and explain all the methods with its pros and cons and finally we can conclude upon the best method.

The ECMAScript 5 isArray Function

function isArray(obj) {
    return Array.isArray(obj);
}

Undoubtedly, this sounds to be the perfect solution as it is compiler’s native function and is expected to be responsive and reliable. However, this is available only in modern browsers that support ECMAScript 5. Look up the ECMAScript 5 compatibility table and you would be disappointed.

Constructor Checking

function isArray(obj) {
    return (typeof obj !== 'undefined' &&
            obj && obj.constructor === Array);
}

Constructor checking is very fast and very accurate. In fact it is too accurate for use. It fails to identify an variable when it has been inherited from an Array. This is, in a way, is helpful when this is actually what you need.

The instanceof Operator

function isArray(obj) {
    return obj instanceof Array;
}

This should have sounded the best and in fact, can be the best if you do not intend to check variables across frames. This method of detection would fail if you try checking it with respect to a variable created in some other window or inside some other frame (or iframe).

Object’s Prototype toString Check

isArray = function(obj) {
    return Object.prototype.toString.call(obj) == "[object Array]";
}

This is a very slick method. Every (almost every) object has a toString method that converts an object to string. And the string representation of the array constructor is consistent and is useful enough for identification. This method is just good enough to fit into our requirements; works in almost all scenarios.

Duck Check

var isArray = function (arg) {
    if (typeof arg === 'object' &&
            ('join' in arg && typeof arg.join === 'function') &&
            ('length' in arg && typeof arg.length === 'number')) {
        return true;
    }
    return false;
}

Straight from the books: “When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.” An array has a couple of very prominent properties like length, push, join, etc. We test the presence of these (duck test).

This method is not always accurate as it is very easy to fool this. I would rather use it for strict interface checking and not type-detection.

Exception Check

var isArray = function (subj) {
    try {
        subj && (subj.length = -1);
        return false;
    }
    catch (er) {
        return true;
    }
};

As most of my acquaintances had to say, this method wins more points for its creativity (than its actual use!) An array’s length cannot be negative and when forced, that raises an error. All said, the try-catch block is super-slow and would beat the whole purpose of using a fast method of detecting array.

Perhaps the Best Method of Array Detection

The most optimized method is perhaps the use of Array.isArray wherever available and otherwise fall back to constructor string checking.

/**
 * Check whether an object is Array or not
 * @type Boolean
 * @param {object} subject is the variable that is
 * tested for Array identity check
 */
var isArray = (function () {
    // Use compiler's own isArray when available
    if (Array.isArray) {
        return Array.isArray;
    } 

    // Retain references to variables for performance
    // optimization
    var objectToStringFn = Object.prototype.toString,
        arrayToStringResult = objectToStringFn.call([]); 

    return function (subject) {
        return objectToStringFn.call(subject) === arrayToStringResult;
    };
}());

Why is this best?

First, it tries to use the built-in isArray function of browsers that has it and that is definitely pretty fast. For the rest unlucky browsers, we use the toString function of objects to identify an Array.

One response

Leave a reply to Newrehmi Cancel reply