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');
2 Answers 2
(function (global) {
function isWindow(o) { return o === global }
})(window)
Just grab the window token at global scope, it can be overwritten
-
\$\begingroup\$
var w = window.open('about:blank'); isWindow(w);
should returntrue
, but would returnfalse
for your code. \$\endgroup\$zzzzBov– zzzzBov2012年03月26日 18:58:05 +00:00Commented Mar 26, 2012 at 18:58 -
1\$\begingroup\$ @zzzzBov you can't do cross VM isWindow checks in a future proof manner. \$\endgroup\$Raynos– Raynos2012年03月26日 19:01:40 +00:00Commented Mar 26, 2012 at 19:01
-
1\$\begingroup\$ and why is that? \$\endgroup\$zzzzBov– zzzzBov2012年03月26日 19:04:15 +00:00Commented Mar 26, 2012 at 19:04
-
\$\begingroup\$ @zzzzBov I think you can - see my response. \$\endgroup\$George Mauer– George Mauer2012年05月25日 21:49:49 +00:00Commented May 25, 2012 at 21:49
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.
function (arg) { return !!arg && arg === arg.self }
is very performant but not as accurate. \$\endgroup\$