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

萝らか妹 提交于 2019-12-30 09:00:15

问题


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?


回答1:


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.




回答2:


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); 



回答3:


See http://perfectionkills.com/how-ecmascript-5-still-does-not-allow-to-subclass-an-array/ for the definitive exposition of the problems in inheriting from Array.

Anyway, in the simplest case, where you are doing

var sort_of_an_array = Object.create(Array.prototype);

you can check using isPrototypeOf:

Array.prototype.isPrototypeOf(sort_of_an_array)

See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isPrototypeOf.




回答4:


How about checking the constructor?

function inherits(obj, proto) {
    return obj.constructor === proto.constructor;
}

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



回答5:


it functions like an array, and for all purposes, it is an array

No. It has no auto-updating length property. See this article why it's quite impossible to subclass Array.

Is there any way to figure out if an object inherits from a particular prototype? I suppose you could iterate through the prototypes, but it feels a tad hacky.

That's just how to do it. A cleaner approach than a self-written function would be to use the instanceof operator:

arr instanceof Array; // true


来源:https://stackoverflow.com/questions/16728438/is-it-possible-to-determine-if-an-object-created-with-object-create-inherits-fro

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!