web-dev-qa-db-ja.com

JavaScriptでグローバルオブジェクトを取得する方法は?

特定の他のモジュールが既にロードされている場合、スクリプトをチェックインしたいです。

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に合格しません。

私は何かが欠けていますか?

74
CoolAJ86

さて、typeof演算子を使用できます。識別子がスコープチェーンのどの場所にも存在しない場合、notReferenceErrorをスローすると、"undefined"が返されます。

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

また、グローバルコードのthis値はグローバルオブジェクトを参照することを忘れないでください。つまり、ifステートメントがグローバルコンテキスト上にある場合は、this.ModuleNameを確認するだけです。

(function () { return this; }());テクニックについて、あなたは正しいです。厳格モードでは、this値はundefinedになります。

厳密モードでは、どこにいてもグローバルオブジェクトへの参照を取得する方法が2つあります。

  • Functionコンストラクターを介して:

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

Functionコンストラクターで作成された関数は、呼び出し元の厳密性を継承しません。'use strict'ディレクティブで本体を開始する場合のみ厳密であり、そうでない場合は厳密ではありません。

この方法は、あらゆるES3実装と互換性があります。

  • indirect eval callを介して、たとえば:

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

ES5では、evalの間接呼び出しで、 グローバル環境 をevalコードの変数環境とレキシカル環境の両方として使用するため、上記が機能します。

評価コードの入力 、ステップ1の詳細を参照してください。

ただし、ES3でevalを間接的に呼び出すと、呼び出し元の変数およびレキシカルな環境がevalコード自体の環境として使用されるため、最後のソリューションはES3実装では機能しないことに注意してください。

そして最後に、厳密モードがサポートされているかどうかを検出するのに役立つことがあります。

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

更新2019

今日のすべてのWebpackとBroccolis、GulpsとGrunts、TypeScriptsとAltScripts、およびcreate-react-appsなどを使用すると、これはまったく役に立ちませんが、単純で古いVanillaJSで作業していて、同形、これはおそらくあなたの最良の選択肢です:

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

Functionコンストラクターは常にグローバルな非厳密スコープで実行されるため、ノードで--use_strictを使用している場合でも、Functionコンストラクターの呼び出しは機能します。

Functionコンストラクターが失敗するのは、CSPヘッダーによってevalが無効になっているブラウザーを使用しているためです。

もちろん、Denoが途中(ノード置換)である場合、Functionコンストラクタも許可されない場合があります。この場合、globalmoduleexportsglobalThis、およびwindowなどのオブジェクトの列挙に戻り、グローバルに徹底的に...:-/

クレイジーな1行ソリューション(オリジナル):

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
23
CoolAJ86

次のように、単にラッパー関数のパラメーターとしてグローバルスコープでこれを使用しないでください。

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

これは、rhino、node、browser、およびjslint(追加の回避策フラグなし)では大丈夫だと思います-これは役立ちますか?何か不足していますか?

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

私自身はウィンドウオブジェクトを使用する傾向がありますが、ヘッドレステストが必要な場合は、env.js(rhino)またはPhantom(ノード)を使用できます。

2
user1410117

どうぞ :)

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

これはどこからでも、たとえば別のクロージャー内から機能するはずです。

編集-投稿をより注意深く読んで、ES5 strictモードに関する部分を見ただけです。誰かがそれについてもう少し光を当てることができますか?これは、覚えている限り、グローバルオブジェクトを取得する方法として受け入れられてきました。

編集2-CMSの答えには、thisのES5 strictモードの扱いに関する詳細があります。

2
Dagg Nabbit

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

これはjslintを渡していません:var Fn = Function, global = Fn('return this')();

自分で試してみてください: http://www.jslint.com/

これは:var Fn = Function, global = new Fn('return this')();

しかし、事実上、これらは [〜#〜] mdn [〜#〜] に従って同じものです。

Functionコンストラクターを(new演算子を使用せずに)関数として呼び出すと、コンストラクターとして呼び出すのと同じ効果があります。

1
senz

以前にこの問題がありましたが、解決策に満足していませんが、動作し、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変数を取得したら、チェックを実行し、スクリプトタイプの最後に

delete GLOBAL.GLOBAL;
0
Roderick Obrist

次のソリューションは以下で機能します。

  • Chrome
  • Node.JS
  • Firefox
  • MSIE
  • Web Workers

コードは次のとおりです。

(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を変更するだけです

0
Remo H. Jansen

私が使用しているものは次のとおりです。

"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';
        }
    }
}
0
Lorenz Lo Sauer