Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What did Douglas Crockford mean by 'constructed in a different window or frame'?

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'));
};
like image 244
user2167582 Avatar asked Mar 04 '14 06:03

user2167582


2 Answers

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 Arrays.

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

like image 153
alex Avatar answered Sep 19 '22 05:09

alex


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.

like image 29
Umur Kontacı Avatar answered Sep 22 '22 05:09

Umur Kontacı