【问题标题】:Javascript check if a variable is the windowJavascript检查变量是否是窗口
【发布时间】:2020-09-14 15:36:49
【问题描述】:

你知道检查变量是否是 javascript 中的窗口对象的好方法吗? 我试过了:

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

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

【问题讨论】:

  • 你能对window做一个等价测试吗? (somevar === window)?'yes':'no'
  • 但是如果是 iframe 窗口就不行了。
  • 我很好奇,你为什么需要这样做?
  • IE11 返回[对象窗口]

标签: javascript cross-browser


【解决方案1】:

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

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

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

【讨论】:

  • self 可以被覆盖,通常用作变量名来保留上下文。
  • @zzzzBov:那么,什么?大多数属性都可以被覆盖,但您很少会在尝试“保留上下文” 时看到这种情况,因为它不会发生在全局范围内,任何自尊的开发人员都会在其他任何地方使用var 声明.只要你参考window.self 而不仅仅是self,你应该没问题。如果这对任何人都很重要,我想他们可以使用window.window 而不是window.self,如果他们愿意的话。它受到保护,不会在大多数现代浏览器中被覆盖。
  • @AndyE,我只是想找到一种更有弹性的方法来检查一个对象是否是学术意义上的window。例如,o = {}; o.self = o; isWindow(o) 将在您的版本中返回 true。 jQuery 检查是否设置了 setInterval,因此 $.isWindow({setInterval:1}) 返回不正确。
  • @zzzzBov:我不相信有一个。 jQuery 开发人员可能选择了setInterval,因为它最不可能被重新用作另一个对象的属性名称,并且所有已知的浏览器都支持它。现代替代方案可能是使用Object.prototype.toString(obj),在大多数浏览器中将返回[object global][object Window],主要例外是IE 7 和更低版本。但是,仍然没有完全恢复。也许在 5 年内。
  • @AndyE,我已经为这个问题添加了一个答案,我认为是有弹性的。它需要对边缘情况进行更多测试。
【解决方案2】:

在 AngularJS 源代码中找到了这个。一个班轮和目标。

return variable && variable.document && variable.location && variable.alert && variable.setInterval;

【讨论】:

  • 当变量未定义时,这将抛出异常(因为函数返回未定义而不是真/假):instanceof Window 是最好的简单检查方法。要使用此 AngularJS 代码,请将其包装在 try{}catch 或 with (typeof variable !== 'undefined')
【解决方案3】:

怎么样:

isWindow = variable === window;

三等号可防止类型强制,否则会使这变得更加困难。

【讨论】:

  • 是的,但我需要一种方法来检查每个窗口,而不仅仅是当前窗口。
  • 比较同一个对象时不需要类型严格检查。
【解决方案4】:

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

(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,我主要关注 5 大巨头:Firefox、Chrome、Safari、Opera 和 IE。如果浏览器标准化为使用'[object Window]',那将是非常好的,但是ECMAScript5规范allows each browser to choose its own value for the [[Class]] property of the global object。从这个意义上说,是的,它是一个相对限制性的实现,但是我认为它比检查arg.self == arg 更有弹性,这很容易被愚弄。
  • 我真的很赞扬你的努力,但我想知道谁需要这么严格。也许图书馆会利用它,但即使是 jQuery 也认为if (obj && typeof obj === "object" && "setInterval" in obj) 已经足够了。什么时候需要有人写o.self = o,有人需要检查它是否是window 对象的可能性有多大?至于弹性,您使用"use strict" 使该函数的弹性甚至不如arg.self === arg,因为当您删除self 属性并将Configurable 属性设置为@ 时会抛出TypeError 987654333@.
  • @AndyE,正如我在之前的评论中提到的,我在学术意义上很好奇。我给自己设定了一个挑战,那就是编写一个(大部分)万无一失的isWindow 函数。显然,覆盖 Object.prototype.toStringFunction.prototype.call 会产生不正确的结果,但我希望有一个可以准确识别窗口对象的函数。
  • @zzzzBov:嗯,我当然可以理解。昨天当你评论我的回答时,我快速浏览了Object.prototype.toString 的内容,并注意到所有主要浏览器中的window.constructor.prototype.toString !== Object.prototype.toString。我花了接下来的 2 个小时试图找出原因,但我仍然不知道答案。有些事情会让你变得那样。
【解决方案5】:
if(variable == window)

这当然只检查变量对象是否是这个窗口(即执行javascript的文档的窗口)。

或者,您可以尝试以下方法:

if(variable.document && variable.location)

并检查是否存在一些窗口字段和/或函数,以便您非常确定它是一个窗口...

【讨论】:

    【解决方案6】:
    variable == window
    

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

    【讨论】:

      【解决方案7】:
      1. window 对象有一个指向自身的属性。所以你可以使用,window.window == window
      2. this 始终保存当前上下文。您可以使用this == window
      3. 如果存在多个frames,每个帧都包含它自己的window 对象。要检查全局 window 对象,可以使用 window.parent == window

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

      【讨论】:

        【解决方案8】:

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

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

        问题是,如果我们有这样的对象,这可能会被愚弄:

        var q = {};
        q.window = q;
        

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

        【讨论】:

          【解决方案9】:
          let isWindowObj = (anObject instanceof Window);
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-07-06
            • 2012-05-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多