如何在JavaScript中获取全局对象?
我想检查一个脚本,如果某个其他模块已经加载。
if (ModuleName) { // extend this module }
但是,如果ModuleName
不存在,则throw
s。
如果我知道Global Object
是什么,我可以使用它。
if (window.ModuleName) { // extend this module }
但是因为我希望我的模块能够同时使用浏览器和node
, rhino
等,所以我不能假设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的名称即可