Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to determine if an object created with Object.create inherits from Array in JavaScript?

Identifying which objects are which is complicated in JavaScript, and figuring out which objects are arrays has something of a hacky solution. Fortunately, it manages to work in both of the following cases:

Object.prototype.toString.call([]);           // [object Array]
Object.prototype.toString.call(new Array());  // [object Array]

Great, no [object Object] in sight! Sadly, this method still manages to fail with this:

var arr = Object.create(Array.prototype);
Object.prototype.toString.call(arr);          // [object Object]

This is frustrating, so say the least. My arr object has all the methods of an array, it functions like an array, and for all purposes, it is an array. Yet JavaScript doesn't provide the tools to identify it as such.

Is there any way to figure out if an object inherits from a particular prototype? I suppose you could iterate through the prototypes like so:

function inherits(obj, proto) {
    while (obj != null) {
        if (obj == proto) return true;
        obj = Object.getPrototypeOf(obj);
    }
    return false;
}

inherits(Object.create(Array.prototype), Array.prototype);  // true

But it feels a tad hacky. Is there any cleaner approach?

like image 572
Alexis King Avatar asked May 24 '13 05:05

Alexis King


2 Answers

How about an instanceof operator? It returns true for all your cases:

[] instanceof Array //true
new Array() instanceof Array //true
Object.create(Array.prototype) instanceof Array //true

However:

Object.create(Array.prototype) instanceof Object //also true

So be careful.

like image 76
Artyom Neustroev Avatar answered Oct 05 '22 23:10

Artyom Neustroev


ECMAScript 5 has introduced Array.isArray() into javascript which provides a reliable way to check. For older browsers, we fix that by (quoted from this book)

function isArray(value) {
    if (typeof Array.isArray === "function") {
         return Array.isArray(value);
    } else {
         return Object.prototype.toString.call(value) === "[object Array]";
    }
}

But i just found out the built-in function Array.isArray does not work correctly when we use Object.create (tested in chrome). I came up with a method that works:

function isArray(value) {
     if (typeof value === "undefined" || value === null) {
          return false;
     }
     do {
          if (Object.prototype.toString.call(value) === "[object Array]") {
               return true;
          }
          value= Object.getPrototypeOf(value);
     } while (value);

     return false;
}

Use it:

var arr = Object.create(Array.prototype);
var arr1 = Object.create(Object.create(Array.prototype));
var arr2 = new Array();
var arr3 = [];
isArray(arr); 
isArray(arr1); 
isArray(arr2); 
isArray(arr3); 
like image 38
Khanh TO Avatar answered Oct 06 '22 01:10

Khanh TO