检查是否为窗口对象。

8

考虑到我的插件可以在任何JS引擎上运行(无论是在浏览器中还是不在浏览器中),

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

    就像我如何知道someVar是否引用了浏览器的window对象。在window中有什么东西可以检查它是否真的是浏览器的window对象吗?

  • 如何检查浏览器的window对象是否真的存在,而不仅仅是包含一个对象的window变量。

    假设您无法单独判断someVar是否是window,并且想将其与实际的浏览器window对象进行匹配,例如someVar === 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({});

我有一种感觉这是一个重复的问题,但我找不到我第一次看到它的地方。


可能是重复的问题:如何检查脚本是否在node.js下运行? - Andy Ray
听起来你想通过检查是否存在window对象来确定你的代码是否在浏览器中运行。你可以尝试查找浏览器可能作为window的一部分实现的功能,比如window.location.href,但是即使这样也不是完全可靠的。那么,你可以尝试确定是否能够返回一个有效的userAgent字符串呢? - Matthew Layton
1
@JanDvorak:不是的。在ES3环境中,它会这样做,但ES5改变了规则,规定当显式传递null时,thisArg不会更改为全局对象。例如,这将返回null:(function () { "use strict"; return (function(){return this}).call(null); })() - Andy E
@AndyE,那么什么时候改为thisArg呢?是否可以使用类似的方法? - John Dvorak
@series0ne 不,我不是在检查脚本是否在浏览器中运行,我正在检查 window 是否为浏览器的 window 对象,而不是命名为 window 的其他对象。 - Joseph
显示剩余3条评论
6个回答

4

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

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

[编辑]

toString()对象原型从 JavaScript 初始版本 1.0 开始就可用了,这是一种检查“类”的传统方法。另外,除了在另一个回答中提到的检查唯一对象属性的方法之外,还有更快执行的方法。

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

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

3
您可以这样获取全局对象...
var global = (1,eval)("this");

是否可以在不使用 eval(或 new Function)的情况下实现? - John Dvorak
@JanDvorak:我非常确定它不是。 - Andy E
1
我无法获取1个字符。实际上,我们在“this”字符串上运行了“eval”。这里涉及到了1 - Tommi
2
@tommi 这只是一种间接调用 eval() 方法的方式。其中的 1 并不重要(它可以是任何有效的表达式),重要的是你不直接调用 *eval()*。这就是你可以在任何地方评估全局作用域代码的方法。但在 IE8 及以下版本中无效。 - Andy E

1
我在了解通过创建实例时发现了它。
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


1

如何

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

除非您测试 _test 是否已经存在于 window 中,如果是,则使用其他值进行测试。 - John Dvorak
另外,完成测试后不要忘记回滚它;-) - John Dvorak
@JanDvorak:是的,但如果没有窗口-我该如何回滚? - georg
这也容易受到 var window = this 的影响,我认为原帖作者可能有点过于担心了。 - Andy E

0

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

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

-1
if( this.window === this )

    


脚本可以被包装在除全局空间以外的其他地方。 - John Dvorak
然后在文件顶部保存对this的引用。天哪。 - Andy Ray
“the script” 指整个文件,我认为没有必要粗鲁。 - John Dvorak
如果是这种情况,我担心提问者的脚本不是一个文件。或者它可能是一个被包含在其他地方的文件。或者它是一个“所有文件都在全局上下文中执行”的环境不适用的环境。或者它是一个不存在文件概念的环境。有很多环境,你不能仅仅假设提问者能够将任何东西放在脚本之外,而且“脚本可能被包装在除全局空间之外的其他东西中”。 - John Dvorak
我曾经工作的一家公司的经理非常喜欢可配置的东西,他希望事情能够尽快完成。当然,编写数据库访问的代码比编写文件访问的代码更快。但是,事实证明JavaScript并不总是存储在文件中,并且远远不总是注入到全局范围内。当然,有不这样做的原因,但是管理员进行PHP注入和JavaScript注入比多编写一个小时的代码要好。有时,这些脚本最终不会在全局范围内,而是在jQuery的click处理程序中。 - John Dvorak

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