Comment obtenir L'objet global en JavaScript?

je veux vérifier dans un script si un autre module est déjà chargé.

if (ModuleName) {
    // extend this module
}

mais si ModuleName n'existe pas, ce throw S.

si je savais ce qu'était le Global Object je pourrais l'utiliser.

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

mais puisque je veux que mon module fonctionne avec les deux navigateurs et node , rhino , etc., Je ne peux pas supposer window .

si je comprends bien, ne fonctionne pas dans l'ES 5 avec "use strict" ;

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

Cela échouera également avec la levée d'une exception

var MyGLOBAL = window || GLOBAL

on dirait qu'il me reste

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

aucun de ces cas ne passera JSLint.

est-ce que je manque quelque chose?

67
demandé sur Qantas 94 Heavy 2010-07-19 00:44:20

10 réponses

Eh bien, vous pouvez utiliser l'opérateur typeof , et si l'identifiant n'existe en aucun endroit de la chaîne scope, il sera pas jeter un ReferenceError , il sera juste retourner "undefined" :

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

rappelez-vous aussi que la valeur this sur le code Global, se réfère à l'objet global, ce qui signifie que si votre déclaration if est sur le contexte global, vous pouvez simplement cocher this.ModuleName .

A propos de la technique (function () { return this; }()); , vous avez raison, sur le mode strict la valeur this sera simplement undefined .

en mode strict, il y a deux façons d'obtenir une référence à L'objet Global, peu importe où vous êtes:

  • à travers le Function constructeur:

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

fonctions créées avec le constructeur Function rigueur de l'interlocuteur, ils ne sont stricts que s'ils commencent leur corps avec la directive 'use strict' , sinon ils ne sont pas stricts.

cette méthode est compatible avec toute implémentation ES3.

  • à travers un indirect eval call , par exemple:

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

ce qui précède fonctionnera parce que dans ES5, appels indirects à eval , utilisez le global environment à la fois, l'environnement variable et l'environnement lexical pour le code eval.

voir les détails sur entrer le Code éval , Étape 1.

mais sachez que la dernière solution ne fonctionnera pas sur les implémentations ES3, car un appel indirect à eval sur ES3 utilisera les environnements variables et lexicaux de l'appelant comme environnements pour le code eval m'.

et enfin, vous pouvez trouver utile de détecter si le mode strict est supporté:

var isStrictSupported = (function () { "use strict"; return !this; })();
85
répondu CMS 2011-07-19 15:30:48

Fou une solution en ligne:

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

.

.

.

Œuvres

  • dans chaque environnement (que j'ai testé)
  • en mode strict
  • et même dans une portée emboîtée

Mise À Jour 2014-Sept-23

cela peut maintenant échouer si les en-têtes HTTP dans le les derniers navigateurs interdisent explicitement eval.

une solution de rechange serait d'essayer / d'attraper la solution originale car seuls les navigateurs sont connus pour exécuter ce type de sous-ensemble de JavaScript.

var global;

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

""

exemple:

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

}());

testé:

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

pourquoi:

en bref: c'est une bizarrerie. Voir les commentaires ci-dessous (ou le message ci-dessus)

Dans strict mode this n'est jamais le global, mais aussi dans strict mode eval fonctionne dans un autre contexte dans lequel this est toujours le mondial.

non-mode strict this est le contexte actuel. Si il n'y a pas de courant contexte, il suppose le global. Une fonction anonyme n'a pas de contexte et donc en mode non-strict assume le global.

Suivant:

il y a une erreur stupide de JavaScript que 99,9% du temps confond juste les gens appelés les 'opérateurs de virgule'.

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
17
répondu CoolAJ86 2014-09-23 20:30:54

pourquoi ne pas simplement utiliser ceci dans une portée globale comme param à une fonction d'enrubannage, comme suit?

(function (global) {
    'use strict';
    // Code
}(this));
5
répondu Edygar de Lima Oliveira 2013-10-02 11:37:18

Ici, vous allez :)

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

cela devrait fonctionner de n'importe où, par exemple à l'intérieur d'une autre fermeture.

Edit-il suffit de lire votre post plus attentivement et a vu la partie sur ES5 mode strict. Quelqu'un peut-il faire la lumière sur qui? Cela a été le moyen de l'objet global pour aussi longtemps que je me souvienne... Bien sûr, j'espère qu'on ne va pas se briser.

Edition 2 - CMS réponse a plus d'infos sur ES5 strictmod's treatment of this .

2
répondu Dagg Nabbit 2010-07-18 20:55:18

je pense que c'est assez bien dans le rhino, noeud, navigateur et avec jslint (sans drapeaux de contournement supplémentaires) - est-ce que cela aiderait? Ai-je raté quelque chose?

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

bien que j'ai moi-même tendance à utiliser l'objet window et si j'ai besoin de tests sans tête je peux utiliser env.js (rhino) ou Phantom (node).

2
répondu Szabi 2012-10-08 13:48:39

j'ai déjà eu ce problème, Je ne suis pas satisfait de la solution, mais il fonctionne et passe JSLint (supposer browser|assumer node):

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

une fois que vous avez le Global var vous pouvez faire votre vérification, et à la fin du script tapez

delete GLOBAL.GLOBAL;
2
répondu Roderick Obrist 2012-11-16 01:36:50

ce n'est pas passer jslint: var Fn = Function, global = Fn('return this')();

Essayez vous-même: http://www.jslint.com/

ce sera: var Fn = Function, global = new Fn('return this')();

mais effectivement ce sont la même chose selon MDN :

invoquer le constructeur de fonctions en tant que fonction (sans utiliser le nouvel opérateur) a le même effet que l'invoquer en tant que constructeur.

1
répondu senz 2013-08-07 08:32:27

ECMAScript va bientôt ajouter ceci à son standard: https://github.com/tc39/proposal-global

Jusqu'à ce qu'il soit fait, c'est ce qui est recommandé:

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
répondu Shaun Lebron 2018-09-29 20:15:14

voici ce que j'utilise:

"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
répondu Lorenz Lo Sauer 2015-02-05 10:36:48

cette solution suivante fonctionne en:

  • Chrome
  • Node.Js
  • Firefox
  • MSIE
  • Travailleurs Sur Le Web

le code est:

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

Vous avez juste besoin de changer X pour le nom de la variable que vous voulez

0
répondu Remo H. Jansen 2015-10-21 20:09:29