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\$
3
  • \$\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
    Commented Mar 26, 2012 at 18:29
  • \$\begingroup\$ Can you explain why you need to know if an object is a window? \$\endgroup\$
    – RoToRa
    Commented Apr 26, 2012 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
    Commented Apr 26, 2012 at 13:12

2 Answers 2

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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