【问题标题】:Check if it's the window object检查它是否是窗口对象
【发布时间】:2013-07-06 18:08:26
【问题描述】:

鉴于我的插件可以在任何 JS 引擎上运行(无论是否在浏览器中),

  • 如何知道某个变量实际上是浏览器window对象。

    比如我怎么知道someVar 是否引用了浏览器window 对象。 window 中有什么东西可以让我检查它是否真的是浏览器 window 对象?

  • 以及如何检查浏览器 window 对象是否确实存在,而不仅仅是一些包含对象的 window 变量。

    假设您无法判断someVar 本身是否为window,并且您想将其与真实 浏览器window 对象(如someVar === window)进行匹配,您如何获得window,您确定它是浏览器 window,而不是来自名为 window 的外部范围的其他对象,或者来自其他环境的其他全局对象?

只是为了澄清一点:

  • 我不是在寻找全局环境。我正在寻找浏览器window 对象。
  • 我没有检查脚本是否在浏览器上运行。

我不能做像if(!window) 这样的事情,因为window 可能只是在范围之外的某个地方声明的另一个对象。

function someFunction(){
  var window = {foo:'bar'};

  (function(){
    console.log(window); //{foo:'bar'}
  }());
}

我无法检查if(window.window === window),因为我也可以进行自引用,并且如前所述,window 可能是来自外部范围的对象:

var bar = {};
bar.bar = bar;
bar.bar.bar.bar.bar.bar === bar; //true

以下可能不起作用,因为脚本可能会被包装或连接到全局空间以外的其他地方。 this 也可以通过 call()apply()bind() 等调用进行修改。

//Stand-alone, I can assume window is global since "this" is the global in global space
(function(window){
  //window may not be window
}(this));

//But when this happens
someNamespace.someFunction = function(){

  (function(window){
    //window may not be window
  }(this));

}

//or this:
someNamespace.someFunction.call({});

我感觉这是复制品,但我找不到第一次看到它的地方。

【问题讨论】:

  • 听起来您想通过检查窗口是否存在来确定您的代码是否在浏览器中运行。您可以尝试寻找浏览器可能作为窗口的一部分实现的功能,例如 window.location.href,但当然即使这样也不是故障安全的。如何确定是否可以返回有效的 userAgent 字符串?
  • (function(){return this}).call(null) 总是有效吗?
  • @JanDvorak:不。在 ES3 环境中它会,但是 ES5 更改了规则,说当显式传递 null 时,thisArg 不会更改为全局对象。例如,这将返回 null:(function () { "use strict"; return (function(){return this}).call(null); })().
  • @AndyE 什么时候改成thisArg呢?可以使用类似的方法吗?

标签: javascript


【解决方案1】:

这不仅会测试当前窗口,还会测试一般窗口:

    if (window.toString() === "[object Window]") {
         // your code here
    }

[编辑]

toString() 对象原型在 JavaScript 初始版本 1.0 中可用,是检查“类”的老式方法。以及这个问题的另一个答案中提到的方法 - 检查唯一的对象属性,这比字符串比较执行得更快。

自 JavaScript 1.4(ECMAScript 第 3 版 1999)以来,我们能够利用 instanceof 运算符来检查对象类,这是该任务的正确方法。

    if (window instanceof Window) {
         // your code here
    }

【讨论】:

    【解决方案2】:

    你可以像这样获取全局对象...

    var global = (1,eval)("this");
    

    【讨论】:

    • 没有eval(或new Function)可以吗?
    • @JanDvorak:我很确定不是。
    • 我无法参与1 char。我们实际上在"this" 字符串上运行eval1 是怎么参与进来的?
    • @tommi 这只是一种间接调用 eval() 的方法。 1 不相关(它可以是任何有效的表达式),重要的是您不直接调用 eval() 。这就是您可以在任何地方评估全局范围内的代码的方式。但它在 IE8 及更低版本中不起作用。
    【解决方案3】:

    怎么样

    function isWindow() {
        _test = 42;
        return window && window._test == 42
    }
    

    【讨论】:

    • 除非您应该测试_test 是否已存在于window 中,如果存在,则使用其他值进行测试。
    • 另外,完成后不要忘记回滚测试;-)
    • @JanDvorak:是的,但是如果没有窗口 - 我该如何回滚?
    • 这也容易受到var window = this 的影响,我认为 OP (也许有点)担心。
    【解决方案4】:

    我在理解通过创建实例时发现了它

    var MyExampleInstace = function MyExampleInstace() {
        console.log(this); // returns undefined in strict mode
        // in not strict mode it will return Window 
    }
    
    new MyExampleInstace(); // will not return and error (this will be fine)
    

    我想创建一个类似的错误

    throw new Error('Please use "new" keyword');
    

    当有人试图调用 MyExampleInstance 时,不是作为实例,而是作为简单的函数,例如:

    MyExampleInstance(); // console should show "Please use "new" keyword
    

    所以最后的结果是:

    var MyExampleInstace = function MyExampleInstace() {
        if (this === undefined || this instanceof Window) throw new Error('Please use "new" keyword');
    }
    

    通过我找到的最简单的方法来检查对象是某种“种类”的对象

    // myVar could be "this" or every var u need
    // That's also opens the way to check the object instance of your MyExampleInstance
    myVar instanceof Window
    

    https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/instanceof

    【讨论】:

      【解决方案5】:

      如果你使用对象窗口支持的一些方法,你可以检查它。 比如postMessage:

      (function(o){ 
       if(!!o.postMessage) console.log("This is my window"); 
       else console.log("This isn't my window");
      })(window);  
      

      【讨论】:

        【解决方案6】:
        if( this.window === this )
        

            

        【讨论】:

        • "脚本可以被包裹在全局空间以外的地方"
        • 然后在文件顶部保存对this 的引用。耶稣。
        • “脚本”指的是整个文件,我假设。没必要粗鲁。
        • 在这种情况下,我担心提问者的脚本不是文件。或者它可能是某个包含在某处的文件。或者也许这是一个“所有文件在全局上下文中执行”的环境不成立。或者也许这是一个不存在文件概念的环境。有很多环境,你不能仅仅假设提问者能够在脚本本身之外的任何地方放置任何东西,并且“脚本可以被包装在全局空间之外的东西中”。
        • 我以前工作过的一家公司的经理非常喜欢可配置的东西,他希望事情能尽快完成。当然,数据库访问编码比文件访问编码要快。好吧,事实证明 javascript 并不总是存储在文件中,而且到目前为止它并不总是被注入到全局范围内。当然,不这样做是有理由的,但是管理员进行的 PHP 注入和 Javascript 注入总比不得不多写一小时的代码要好。而且,有时这些小脚本最终不在全局范围内,而是一个 jQuery click 处理程序。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-30
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多