如何在JavaScript中获取全局对象?

我想检查一个脚本,如果某个其他模块已经加载。

if (ModuleName) { // extend this module } 

但是,如果ModuleName不存在,则throw s。

如果我知道Global Object是什么,我可以使用它。

 if (window.ModuleName) { // extend this module } 

但是因为我希望我的模块能够同时使用浏览器和noderhino等,所以我不能假设window

据我了解,这在ES 5中不适用于"use strict" ;

 var MyGLOBAL = (function () {return this;}()); // MyGlobal becomes null 

这也将失败,抛出exception

 var MyGLOBAL = window || GLOBAL 

所以,我似乎离开了

 try { // Extend ModuleName } catch(ignore) { } 

这些情况都不会通过JSLint。

我错过了什么?

那么你可以使用typeof运算符,如果这个标识符不在scope链的任何地方,它不会抛出一个ReferenceError ,它只会返回"undefined"

 if (typeof ModuleName != 'undefined') { //... } 

还要记住全局代码上的this值是指全局对象,这意味着如果你的if语句在全局上下文中,你可以简单地检查this.ModuleName

关于(function () { return this; }()); 技术,你是对的,在严格的模式下, this值将被简单地undefined

在严格模式下,有两种方式可以获得对Global对象的引用,不pipe你在哪里:

  • 通过Function构造函数:

     var global = Function('return this')(); 

使用Function构造函数创build的Function不会inheritance调用者的严格性,只有在用'use strict'指令启动它们时才'use strict' ,否则它们不是严格的。

该方法与任何ES3实现兼容。

  • 通过间接eval ,例如:

     "use strict"; var get = eval; var global = get("this"); 

因为在ES5中间接调用eval ,使用全局环境作为eval代码的可变环境和词法环境。

有关input评估代码的详细信息,请参阅步骤1。

但请注意,最后一个解决scheme在ES3实现上不起作用,因为间接调用ES3上的eval将使用调用者的variables和词法环境作为eval代码本身的环境。

最后,您可能会发现检测是否支持严格模式很有用:

 var isStrictSupported = (function () { "use strict"; return !this; })(); 

疯狂的单线解决scheme:

 var global = Function('return this')() || (42, eval)('this'); 

作品

  • 在每个环境(我testing)
  • 严格的模式
  • 甚至在一个嵌套的范围内

更新2014年9月23日

如果最新浏览器中的HTTP标头明确禁止eval,现在可能会失败。

解决方法是尝试/捕获原始解决scheme,因为只有浏览器可以运行这种types的JavaScript子集。

 var global; try { global = Function('return this')() || (42, eval)('this'); } catch(e) { global = window; } 

“`

例:

 (function () { var global = Function('return this')() || (42, eval)('this'); console.log(global); // es3 context is `global`, es5 is `null` (function () { "use strict"; var global = Function('return this')() || (42, eval)('this'); console.log(global); }()); // es3 and es5 context is 'someNewContext' (function () { var global = Function('return this')() || (42, eval)('this'); console.log(global); }).call('someNewContext'); }()); 

testing:

  • Chrome v12
  • Node.JS v0.4.9
  • Firefox v5
  • MSIE 8

为什么:

总之:这是一个奇怪的怪癖。 见下面的评论(或上面的post)

strict mode this绝不是全球性的,而且在strict mode eval在一个单独的环境中运作,在这个环境中, this一直是全球性的。

在非严格模式下, this是当前的上下文。 如果没有当前的情况下,它假定全球。 匿名函数没有上下文,因此在非严格模式下假定为全局。

Sub Rant:

JavaScript有一个愚蠢的错误特征,99.9%的时间混淆了被称为“逗号操作符”的人。

 var a = 0, b = 1; a = 0, 1; // 1 (a = 0), 1; // 1 a = (0, 1); // 1 a = (42, eval); // eval a('this'); // the global object 

为什么不把它作为一个封装函数的参数在全局范围内使用呢?

 (function (global) { 'use strict'; // Code }(this)); 

干得好 :)

 var globalObject = (function(){return this;})(); 

这应该从任何地方起作用,例如在另一个closures中。

编辑 – 只要仔细阅读你的文章,看到关于ES5严格模式的部分。 任何人都可以谈到更多的光? 只要我能记住,这就是我们所接受的全球对象的接受方式……我当然希望它不会被打破。

编辑2 – CMS的答案有更多的信息在ES5严格模式的处理。

我认为这在犀牛,节点,浏览器和jslint (没有额外的解决方法标志)是非常好的 – 这会有帮助吗? 我错过了什么吗?

 x = 1; (function(global){ "use strict"; console.log(global.x); }(this)); 

虽然我自己倾向于使用窗口对象,如果我需要无头testing,我可以使用env.js(rhino)或Phantom(node)。

我之前有过这个问题,我对解决scheme不满意,但它工作并传递了JSLint(假定浏览器|假设节点):

 "use strict"; var GLOBAL; try{ /*BROWSER*/ GLOBAL = window; }catch(e){ /*NODE*/ GLOBAL = global; } if(GLOBAL.GLOBAL !== GLOBAL){ throw new Error("library cannot find the global object"); } 

一旦你有GLOBAL var你可以做你的检查,并在脚本types的末尾

 delete GLOBAL.GLOBAL; 

这不是传递jslint: var Fn = Function, global = Fn('return this')();

尝试一下: http : //www.jslint.com/

这将会: var Fn = Function, global = new Fn('return this')();

但根据MDN,这些都是有效的:

作为一个函数调用Function构造函数(不使用new运算符)与调用构造函数具有相同的效果。

这是我正在使用的:

 "use strict"; if(this && this.hasOwnProperty && !this.hasOwnProperty('globalScope')){ try { globalScope = Function('return this')(); }catch(ex){ if(this.hasOwnProperty('window')){ globalScope = window; }else{ throw 'globalScope not found'; } } } 

以下解决scheme适用于:

  • Node.js的
  • 火狐
  • MSIE
  • networking工作者

代码是:

 (function (__global) { // __global here points to the global object })(typeof window !== "undefined" ? window : typeof WorkerGlobalScope !== "undefined" ? self : typeof global !== "undefined" ? global : Function("return this;")()); 

您只需要将X更改为您想要的variables的名称即可

Interesting Posts