What does Douglas Crockford mean when he wrote the is_array()
test saying that it will fail to identify arrays that were constructed in a different window or frame?
var is_array = function (value) {
return value &&
typeof value === 'object' &&
value.constructor === Array;
Why does the following work across windows and frames?
var is_array = function (value) {
return value &&
typeof value === 'object' &&
typeof value.length === 'number' &&
typeof value.splice === 'function' &&
!(value.propertyIsEnumerable('length'));
};
For example, if you have an iframe
, which has its own window
, any Array
constructed in there will fail another window
's test. That's because of the last condition, which assumes the current window
's Array
, which is a different object.
var isArray = document.querySelector("iframe").contentWindow.Array === Array;
// false (wrong, it *is* an array)
jsFiddle.
The latter works through knowing that typeof
always says an Array
is an "object"
, as well as looking for properties that exist on Array
s.
However, it can be fooled, by constructing an object that looks like an array.
var isArray = is_array(Object.create({length: 0, splice: function() {}}));
// true (wrong, it *isn't* an array)
jsFiddle.
Another method is to invoke Object
's toString()
method on it, which will return the internal class.
var isArray = ({}).toString.call(value) == "[object Array]";
// true (correct, it's an array)
jsFiddle.
This works in a multi-window
environment and can't be tricked (though there is more overhead examining it this way, but never likely to be a bottleneck).
I think alex's solution is better than Crockford's. This answer is to point the flaw in Crockford's solution.
See this:
I purposefully created a faulty object.
function Stupid(){}
Stupid.prototype.length = 0;
Stupid.prototype.splice = function () {}
var stupid = new Stupid();
is_array(stupid);
// true
Obviously, if you see someone setting length to the prototype, you have every right to smash their head to the wall.
But this is valid:
function Mediocre(){
Object.defineProperty(this, 'length', {
get: function () { return 42; },
enumerable: false
});
}
Mediocre.prototype.splice = function () {}
var m = new Mediocre();
is_array(m);
// true
So, you shouldn't try to outsmart the usual/common methods, because you can't guess what the other developers are going to do.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With