6
\$\begingroup\$

While I'm aware of various different means of checking if a variable is a Window object in JavaScript, I'm interested in writing a function that is more accurate and resilient.

For example, jQuery uses:

isWindow: function( obj ) {
    return obj != null && obj == obj.window;
}

which will return an incorrect result for:

var o = {};
o.window = o;
$.isWindow(o); //returns `true`, even though `o` is not a window object

For purposes of this question, assume that the browser's native functions and objects have not been modified at the time of initialization.


Currently my code is:

(function (w) {
    "use strict";
    var wStr;
    wStr = Object.prototype.toString.call(w);
    if (!w.isWindow) {
        w.isWindow = function (arg) {
            var e,
                str,
                self,
                hasSelf;

            //Safari returns `DOMWindow`
            //Chrome returns `global`
            //Firefox, Opera & IE9 return `Window`
            str = Object.prototype.toString.call(arg);
            switch (wStr) {
            case '[object DOMWindow]':
            case '[object Window]':
            case '[object global]':
                return str === wStr;
            }
            if ('self' in arg) {
                //`'self' in arg` is true if `'self'` is in `arg` or a prototype of `arg`
                hasSelf = arg.hasOwnProperty('self');
                //`hasSelf` is true only if `'self'` is in `arg`
                try {
                    if (hasSelf) {
                        self = arg.self;
                    }
                    delete arg.self;
                    if (hasSelf) {
                        arg.self = self;
                    }
                } catch (e) {
                    //IE 7&8 throw an error when `window.self` is deleted
                    return true;
                }
            }
            return false;
        };
    }
}(window));

A few assertions:

console.assert(isWindow(window), '"window" is a window');

var o = {};
o.self = o;
o.window = o;
console.assert(!isWindow(o), '"o" is not a window');

var w = window.open('about:blank');
console.assert(isWindow(w), '"w" is a window');

var x = window.open('http://www.example.com');
console.assert(isWindow(x), '"x" is a window');
\$\endgroup\$
  • \$\begingroup\$ Also note, I'd prefer accuracy over performance. function (arg) { return !!arg && arg === arg.self } is very performant but not as accurate. \$\endgroup\$ – zzzzBov Mar 26 '12 at 18:29
  • \$\begingroup\$ Can you explain why you need to know if an object is a window? \$\endgroup\$ – RoToRa Apr 26 '12 at 9:23
  • \$\begingroup\$ There are niche cases where I need to know if an object is a window. I'm aware of alternative, less resilient methods for checking for a window type (see this related question), and I'm mostly just curious in an academic sense as to whether a function can be written that will accurately check the type of the object. \$\endgroup\$ – zzzzBov Apr 26 '12 at 13:12
1
\$\begingroup\$

What about taking advantage of the (stupid) fact that the context parameter inside a function invoked without call or apply will be the window?

mYApp.isWindow = function(obj) {
  if(!obj)
    return false
  return obj === (function() { return this})() //is this the window
     || obj.eval && obj.eval.call && obj.eval("this === (function(){ return this })()") //is that another window
     || false; //make undefined false
};

Seems to even work when wrapped in a with. That being said, you might have legitimate reasons to want to test for this but I can't think of any.

Edit: Added check for 'other' window. You could probably add some finagling to check that eval isn't a stub that always returns true. So if it returns true for example you could generate two random numbers, add them together, and then pass them into the eval string and have it add those numbers and confirm the result is indeed accurate. Let's be honest though, that's stupid, if someone wants to trick you that bad, they'll find a way.

\$\endgroup\$
0
\$\begingroup\$
(function (global) {
    function isWindow(o) { return o === global }
})(window)

Just grab the window token at global scope, it can be overwritten

\$\endgroup\$
  • \$\begingroup\$ var w = window.open('about:blank'); isWindow(w); should return true, but would return false for your code. \$\endgroup\$ – zzzzBov Mar 26 '12 at 18:58
  • 1
    \$\begingroup\$ @zzzzBov you can't do cross VM isWindow checks in a future proof manner. \$\endgroup\$ – Raynos Mar 26 '12 at 19:01
  • 1
    \$\begingroup\$ and why is that? \$\endgroup\$ – zzzzBov Mar 26 '12 at 19:04
  • \$\begingroup\$ @zzzzBov I think you can - see my response. \$\endgroup\$ – George Mauer May 25 '12 at 21:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for?Browse other questions tagged or ask your own question.