【问题标题】:How to get the global object in JavaScript?如何在 JavaScript 中获取全局对象?
【发布时间】:2010-07-18 20:44:20
【问题描述】:

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

if (ModuleName) {
    // extend this module
}

但是如果ModuleName不存在,那throws。

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

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

但由于我希望我的模块同时适用于浏览器和noderhino 等,我不能假设window

据我了解,这在带有 "use strict" 的 ES 5 中不起作用;

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

这也会失败并抛出异常

var MyGLOBAL = window || GLOBAL

看来我只剩下了

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

这些情况都不会通过 JSLint。

我错过了什么吗?

【问题讨论】:

  • 注意“var Fn = Function, global = Fn('return this')();”将通过 JSLint,因为 JSLint 期望带有大写字母的函数是构造函数并使用“new”调用。不过,这是一个简单的解决方法。
  • 这也通过了 JSLint,并且不需要额外的 Fn 变量:var global = (function (fn) { return fn('return this'); }(Function));
  • @ahuth 你需要一个额外的()
  • 你可以像这样获取全局对象(没有 eval 或 Function 构造函数):var global = (function(){return this}).apply(null)。更多信息developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
  • 注意:如果你使用严格模式,apply(null) 不会给出全局对象:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…

标签: javascript global


【解决方案1】:

好吧,您可以使用typeof 运算符,如果标识符不存在于作用域链的任何位置,它不会抛出ReferenceError,它只会返回"undefined":

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

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

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

在严格模式下,无论您身在何处,都有两种方法可以获取对 Global 对象的引用:

  • 通过Function 构造函数:

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

使用Function 构造函数创建的函数不继承调用者的严格性,它们只有在以'use strict' 指令开始其主体时才是严格的,否则它们是非严格的。

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

  • 通过间接的eval 调用,例如:

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

上述方法会起作用,因为在 ES5 中,对 eval 的间接调用,使用 global environment 作为 eval 代码的变量环境和词法环境。

请参阅Entering Eval Code 的详细信息,第 1 步。

但请注意,最后一个解决方案不适用于 ES3 实现,因为在 ES3 上对 eval 的间接调用将使用调用者的变量和词法环境作为 eval 代码本身的环境。

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

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

【讨论】:

  • +1 @CMS - 我已经数不清我在这个网站上阅读了多少次你的答案。谢谢大佬。
  • 可能很明显的问题:为什么要使用“use strict”然后规避它的影响之一?获取全局上下文的唯一方法是不是有点 hacky?
  • @Walkerneo 一个原因可能是我们真的不应该向全局范围添加任何东西(尽管它可能很有用,比如当我们需要导出库 API 时)。另外,我相信“this”的使用受到限制(在严格模式下),因为它所指的内容可能并不总是很明显。实现这一点使得获取对全局对象的引用变得困难。
  • 很遗憾, Function('return this') 不起作用。在 Chrome 中,我得到:EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not a allowed source of script in the following Content Security Policy directive:“script-src 'self' 'unsafe-inline'”。
  • @CMS 请注意,Function 可以在子作用域中被覆盖甚至隐藏。最好使用var global = (() => {}).constructor('return this')();
【解决方案2】:

2019 年更新

对于当今所有的 Webpacks 和 Broccolis,Gulps 和 Grunts,TypeScripts 和 AltScripts,以及 create-react-apps 等,这非常没用,但如果你只是在使用普通的、旧的 VanillaJS 和你想让它同构,这可能是你最好的选择:

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

即使在节点中使用--use_strict,Function 构造函数调用也会起作用,因为 Function 构造函数总是在全局非严格范围内执行。

如果 Function 构造函数失败,那是因为您在浏览器中的 CSP 标头禁用了 eval

当然,随着 Deno 的到来(节点替换),他们也可能不允许 Function 构造函数,在这种情况下,它会返回枚举对象,如 globalmoduleexportsglobalThiswindow,然后是彻底的全局鸭式检查...:-/

疯狂的单行解法(原创):

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

.

.

.

作品

  • 在每个环境中(我测试过)
  • 在严格模式下
  • 甚至在嵌套范围内

2014 年 9 月 23 日更新

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

一种解决方法是尝试/捕获原始解决方案,因为已知只有浏览器可以运行这种类型的 JavaScript 子集。

var global;

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

    (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');

    }());

Tested:
---

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

Why:
---

In short: it's some weird quirk. See the comments below (or the post above)


In `strict mode` `this` is never the global, but also in `strict mode` `eval` operates in a separate context in which `this` *is* always the global.

In non-strict mode `this` is the current context. If there is no current context, it assumes the global. An anonymous function has no context and hence in non-strict mode assumes the global.

Sub Rant:

There's a silly misfeature of JavaScript that 99.9% of the time just confuses people called the 'comma operator'.

    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

【讨论】:

  • 这不仅仅是一个奇怪的怪癖,我在回答中将其描述为间接调用eval。在 ES5 中,仅当CallExpression 由满足两个条件的MemberExpression 形成时,才能直接调用eval: 1. 引用的基值是环境记录。 2.引用名称为"eval",任何其他方式调用eval都会导致间接调用。请小心,因为这种行为在 ES3 中不起作用,因为 直接调用 到 eval 的概念不存在。使用 ES3 实现(例如 IE8)尝试 this example
  • @CoolAJ86,你的新代码也适用于 ES3 实现,但是如果你仔细检查它,你会发现间接的 eval 部分根本不需要,你只需要@ 987654341@,正如我所描述的,“使用Function 构造函数创建的函数不会继承调用者的严格性”,这意味着该函数的返回值将是始终全局对象, -无论实施-。在 || 运算符右侧的 eval 调用永远不会进行,因为该函数将始终产生一个真实值(全局 obj)。
  • 您可能会通过声明 a = 0, 1; // 0(a = 0), 1; // 0 来增加逗号混淆,因为这两个表达式都返回 1。也许// a = 0 会更好。
  • 嗯...当我测试它时我可以发誓我得到 0... 但你绝对是对的。更新了答案
  • 表达式(42, eval)('this') 何时被计算?换句话说,Function('return this')() 什么时候会是假的?
【解决方案3】:

为什么不简单地将 this 在全局范围内用作包装函数的参数,如下所示?

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

【讨论】:

  • 令人惊讶的是,还没有人指出这并没有真正增加 Szabolcs Kurdi 的答案一年前没有提供的任何东西。它没有解决那里的 cmets 中提出的问题,即它需要在全局范围内调用才能工作,但至少您的回答确实承认了这一点。
  • 这在 NodeJS 模块中不起作用,其中 this === module.exports.
【解决方案4】:

给你:)

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

这应该可以在任何地方工作,例如在另一个闭包中。

编辑 - 仔细阅读您的帖子并查看有关 ES5 严格模式的部分。任何人都可以对此有所了解吗?从我记事起,这就是获取全局对象的公认方式……我当然希望它不会最终被破坏。

编辑 2 - CMS 的答案有更多关于 ES5 严格模式处理 this 的信息。

【讨论】:

  • @Eduardo ―无。
【解决方案5】:

我认为这在 rhino、node、浏览器和 jslint 中几乎没问题(没有额外的解决方法标志) - 这有帮助吗?我错过了什么吗?

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

虽然我自己倾向于使用 window 对象,如果我确实需要无头测试,我可以使用 env.js (rhino) 或 Phantom (node)。

【讨论】:

  • 它在没有其他选项的情况下通过了 jslint(如果你去掉 x=1 的例子),虽然我猜它只是一种选择(虽然优雅是一个高度主观的因素)。
  • 您错过了this 可能不引用全局对象的事实。
  • 据我所知,如果在全局范围(浏览器、犀牛、节点)中使用,它确实指的是全局范围,但我可能错了。你能展示一个示例虚拟机,它的工作方式不同吗?谢谢!
  • @SzabolcsKurdi 你是对的,当在全局范围内使用时,'this' 将是全局范围。问题是无法保证该函数将在全局范围内执行。例如,如果将此 get 放入库中并包装在立即调用的函数中。我们真正在寻找的是一种获取全局范围的方法不管它被调用的范围。
【解决方案6】:

ECMAScript 将很快将其添加到其标准中: https://github.com/tc39/proposal-global

在完成之前,这是推荐的:

var getGlobal = function () {
    // the only reliable means to get the global object is
    // `Function('return this')()`
    // However, this causes CSP violations in Chrome apps.
    if (typeof self !== 'undefined') { return self; }
    if (typeof window !== 'undefined') { return window; }
    if (typeof global !== 'undefined') { return global; }
    throw new Error('unable to locate global object');
};

【讨论】:

  • This 有问题; 2.9 之前的所有版本都受到影响,Moment 是一个非常受欢迎的库。
【解决方案7】:

这没有通过 jslint:var Fn = Function, global = Fn('return this')();

自己试试吧:http://www.jslint.com/

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

但根据MDN,实际上这些是同一件事:

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

【讨论】:

  • 有趣的观察。
【解决方案8】:

以下解决方案适用于:

  • Node.JS
  • 火狐
  • MSIE
  • 网络工作者

代码是:

(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 更改为您想要的变量的名称

【讨论】:

    【解决方案9】:

    我之前遇到过这个问题,我对解决方案不满意,但它可以工作并通过 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,你就可以进行检查,并在脚本类型的末尾

    delete GLOBAL.GLOBAL;
    

    【讨论】:

    • 我确认这种方法是干净且有用的。不知道为什么与其他答案中的所有邪恶解决方案相比,它没有得到更多的支持。
    【解决方案10】:

    这是我正在使用的:

    "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';
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2023-01-29
      • 2014-10-14
      • 1970-01-01
      • 2013-02-12
      • 1970-01-01
      • 1970-01-01
      • 2019-08-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多