Javascript如何检查一个变量是否为窗口(window)?

14

你知道如何在Javascript中检查一个变量是否为window对象吗?我已经尝试过:

var variable=window;
Object.prototype.toString.call(variable);

在 Firefox 中返回 "[object Window]",但在 IE 中返回 "[object Object]",所以这不是正确的方法。你知道一个准确的方式来检查吗?


你能否对 window 进行等价性测试?(somevar === window)?'yes':'no' - Stephen Ierodiaconou
但如果它是一个iframe窗口,它就不起作用。 - mck89
我很好奇,你为什么需要这样做? - Casey Chu
IE11 返回 [object Window]。 - jsnjack
10个回答

13

是的,但我需要一种检查每个窗口而不仅仅是当前窗口的方法

有几种方法可以做到这一点。 最简单的方法是检查窗口对象上的一个或两个已知属性。 还有self属性 - 对于每个窗口,您可以检查self属性是否等于该窗口对象:

myvar.self == myvar;
window.self == window;
frameElement.contentWindow.self == frameElement.contentWindow;

2
self 可以被覆盖,通常用作变量名以保留上下文。 - zzzzBov
@zzzzBov:那又怎样?大多数属性都可以被覆盖,但是当尝试保留上下文时很少会看到这种情况,因为它不会发生在全局范围内,并且任何有自尊心的开发人员都会在其他任何地方声明var。只要引用window.self而不仅仅是self,你就应该没问题了。如果对任何人来说这很重要,我想他们可以使用window.window而不是window.self,如果他们愿意的话。在大多数现代浏览器中,它受到防止被覆盖的保护。 - Andy E
1
@AndyE,我只是试图在学术意义上找到一种更具弹性的方法来检查对象是否为“window”。例如,“o = {}; o.self = o; isWindow(o)”将在您的版本中返回true。而“jQuery”则会检查是否设置了“setInterval”,因此“$.isWindow({setInterval:1})”会返回错误结果。 - zzzzBov
@zzzzBov: 我不相信有这样一个方法。jQuery开发者可能选择了setInterval,因为它最不可能被另一个对象重复使用作为属性名称,并且所有已知的浏览器都支持它。现代的替代方法可能是使用Object.prototype.toString(obj),它将在大多数浏览器中返回[object global][object Window],主要异常情况是IE 7及以下版本。尽管如此,它仍然不完全弹性。也许在5年内会有改变。 - Andy E
@AndyE,我已经给这个问题添加了一个答案,我觉得它很有弹性。但是它需要更多边缘情况的测试。 - zzzzBov
@zzzz:哎呀,我没意识到。那你应该已经自己搞定了 Object.prototype.toString 这个东西了吧 :-) - Andy E

5
在AngularJS源代码中发现了这个一行代码,非常精准。
return variable && variable.document && variable.location && variable.alert && variable.setInterval;

当变量未定义时,这将抛出异常(因为函数返回undefined而不是true/false):instanceof Window是最好的简单方法来检查。要使用这个AngularJS代码,请将其包装在try{}catch或with(typeof variable !== 'undefined')中。 - Raymond Naseef
如果 setInterval 函数存在,则返回该函数。在结尾添加 && true 可以解决此问题。 - Infigon

1

在尝试了许多选项后,我相信这是跨浏览器检测对象是否为窗口的最准确方法:

(function () {
    "use strict";
    var wStr;
    wStr = Object.prototype.toString.call(window);
    function isWindow(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;
        }
        ///window objects always have a `self` property;
        ///however, `arg.self == arg` could be fooled by:
        ///var o = {};
        ///o.self = o;
        if ('self' in arg) {
            //`'self' in arg` is true if
            //the property exists on the object _or_ the prototype
            //`arg.hasOwnProperty('self')` is true only if
            //the property exists on the object
            hasSelf = arg.hasOwnProperty('self');
            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;
    }
}());

我需要进行更严格的单元测试,所以告诉我任何出现的不一致之处。


我更新了你的答案,因为有一个错误,然后我测试了一下,似乎它可以工作,但我认为第一部分太过严格,因为几乎每个浏览器都有自己将窗口转换为字符串的方式,可能有超过3种变体。 - mck89
@mck89,我主要关注的是五大浏览器:Firefox、Chrome、Safari、Opera和IE。如果浏览器规范化使用'[object Window]',那将是非常好的,然而,ECMAScript5规范允许每个浏览器选择全局对象的[[Class]]属性的自己的值。从这个意义上说,它是相对限制性的实现,但我认为它比检查arg.self == arg更具弹性,后者很容易被欺骗。 - zzzzBov
我确实很赞赏你的努力,但我想知道谁需要如此严格。也许一个库会用到它,但即使是jQuery认为 if (obj && typeof obj === "object" && "setInterval" in obj) 已经足够了。什么时候有人需要编写 o.self = o,并且有多大可能有人需要检查它是否是一个 window 对象呢?至于弹性,你使用的 "use strict" 使函数比 arg.self === arg 更不具弹性,因为当你删除一个 self 属性并且该属性的 Configurable 属性设置为 false 时,将抛出 TypeError - Andy E
1
@zzzzBov:我确实能理解那种感觉。昨天当你评论我的答案时,我快速查看了Object.prototype.toString的内容,并注意到在所有主要浏览器中,window.constructor.prototype.toString !== Object.prototype.toString。接下来的两个小时里,我一直试图弄清楚为什么,但我仍然不知道答案。有些事情就是这样让你困扰。 - Andy E
@zzzzBov: 在Chrome、Firefox和IE 9+中,DOMWindow/Window通过原型链继承自Object的属性和方法。这种继承包括toLocaleString(),它与toString()几乎相同。我之前困惑的是为什么toString()没有被继承,即使结果相同(除了Chrome返回window.toString()“[object DOMWindow]”,而不是“[object global]”)。 - Andy E
显示剩余2条评论

1

只需要这样怎么样:

isWindow = variable === window;

三个等号可以防止类型强制转换,否则这将使得这个过程变得更加困难。


2
是的,但我需要一种方法来检查每个窗口,而不仅仅是当前的窗口。 - mck89
当比较相同对象时,类型严格检查是不必要的。 - Andy E

0
variable == window

有人仍然可以定义一个名为window的局部变量。我不确定是否有一种方法能够抵御所有这些恶作剧。有人可以创建一个对象,复制大多数窗口属性和函数,包括toString


0
if(variable == window)

当然,这只检查变量对象是否为此窗口(即执行 JavaScript 的文档窗口)。
或者,你可以尝试类似这样的东西:
if(variable.document && variable.location)

检查一下几个窗口字段或函数的存在,这样你就可以相当确定它是一个窗口了...


0
  1. window 对象有一个指向自身的属性。因此,您可以使用 window.window == window
  2. this 始终保持当前上下文。您可以使用 this == window
  3. 如果存在多个 frame,每个框架都包含自己的 window 对象。要检查全局的 window 对象,可以使用 window.parent == window

console.log("1 : " + (window.window == window))
console.log("2 : " + (window.window == this))
console.log("3 : " + (window.parent == window))


0

这里是您可以对窗口(w)执行的“几乎”所有检查:

  • 如果您要在任何上下文中检查对象是否为window,则应执行此操作
// the `false` branch is for `boolean` TypeScript consistency and tests
const isWindow = (object) => object && object.constructor.name === 'Window' || false;


isWindow() // => false
isWindow(window) // => true
isWindow(window.parent) // => true
isWindow(window.top) // => true

进行这种检查的原因是测试运行程序在各种iframes中调用本地方法遇到各种问题,特别是instanceof

  • 如果您想检查窗口是否为顶部/父级/上下文/一个
const win = window;

// TOP
console.log(win === win.top)

// PARENT
console.log(win === win.parent)

// CONTEXT
console.log(win === win.self)

// ONE WINDOW
console.log(win === win.self && win === win.top)

希望这能有所帮助。

-1

由于window是全局变量,而全局变量是全局对象的属性,因此window.window将等于window。所以你可以测试:

if (mysteryVariable.window == mysteryVariable)
    ...

问题在于,如果我们有这样一个对象,它就会被欺骗:
var q = {};
q.window = q;

如果那不太可能,那么您可以使用这段代码。

-1
let isWindowObj = (anObject instanceof Window);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接