簡體   English   中英

JavaScript 中如何獲取全局對象?

[英]How to get the global object in JavaScript?

如果某個其他模塊已加載,我想簽入腳本。

if (ModuleName) {
    // extend this module
}

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

如果我知道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。

我錯過了什么嗎?

好吧,你可以使用typeof運算符,如果標識符不存在於作用域鏈的任何地方,它不會拋出ReferenceError ,它只會返回"undefined"

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

還要記住,全局代碼上的this值是指全局對象,這意味着如果你的if語句是在全局上下文中,你可以簡單地檢查this.ModuleName

關於(function () { return this; }()); 技術,你是對的,在嚴格模式下, this值將只是undefined

在嚴格模式下,無論您身在何處,都有兩種方法可以獲取對 Global 對象的引用:

  • 通過Function構造函數:

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

使用Function構造函數創建的Function不繼承調用者的嚴格性,只有當它們以'use strict'指令開始它們的主體時它們才是'use strict' ,否則它們是非嚴格的。

此方法與任何 ES3 實現兼容。

  • 通過間接eval調用,例如:

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

以上將起作用,因為在 ES5 中,對eval間接調用將全局環境用作 eval 代碼的變量環境和詞法環境。

請參閱輸入評估代碼,步驟 1 的詳細信息。

但請注意,最后一個解決方案不適用於 ES3 實現,因為在 ES3 上對eval的間接調用將使用調用者的變量和詞法環境作為 eval 代碼本身的環境。

最后,您可能會發現檢測是否支持嚴格模式很有用:

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

2019 年更新

對於當今所有的 Webpacks 和 Broccolis、Gulps 和 Grunts、TypeScripts 和 AltScripts 以及 create-react-apps 等,這非常無用,但是如果您只是使用普通的、舊的、VanillaJS 並且您想要制作它同構,這可能是你最好的選擇:

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

即使在 node 中使用--use_strict函數構造函數調用也能工作,因為函數構造函數總是在全局非嚴格范圍內執行。

如果 Function 構造函數失敗,那是因為您使用的瀏覽器中的eval被 CSP 標頭禁用。

當然,隨着 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

為什么不簡單地在全局范圍內使用 this 作為包裝函數的參數,如下所示?

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

干得好 :)

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

這應該適用於任何地方,例如在另一個閉包中。

編輯 - 只需更仔細地閱讀您的帖子,並查看有關 ES5 嚴格模式的部分。 任何人都可以對此有所了解嗎? 只要我記得,這一直是獲取全局對象的公認方式......我當然希望它不會最終被破壞。

編輯 2 - CMS 的回答有更多關於 ES5 嚴格模式處理this

我認為這在犀牛、節點、瀏覽器和jslint (沒有額外的解決方法標志)中非常好 - 這有幫助嗎? 我錯過了什么嗎?

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

雖然我自己傾向於使用 window 對象,如果我確實需要無頭測試,我可以使用 env.js (rhino) 或 Phantom (node)。

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

這不是傳遞 jslint: var Fn = Function, global = Fn('return this')();

自己試試: http : //www.jslint.com/

這將: var Fn = Function, global = new Fn('return this')();

但實際上,根據MDN,它們是相同的:

將 Function 構造函數作為函數調用(不使用 new 運算符)與將其作為構造函數調用具有相同的效果。

以下解決方案適用於:

  • 鉻合金
  • 節點JS
  • 火狐
  • 微信公眾平台
  • 網絡工作者

代碼是:

(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 更改為您想要的變量名稱

這是我正在使用的:

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

我以前遇到過這個問題,我對解決方案不滿意,但它可以工作並通過 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;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM