Come ottenere l’object globale in JavaScript?

Voglio controllare uno script se un altro modulo è già stato caricato.

if (ModuleName) { // extend this module } 

Ma se ModuleName non esiste, questo throw s.

Potrei usarlo se sapessi qual è l’ Global Object .

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

Ma dal momento che voglio che il mio modulo funzioni con entrambi i browser e node , rhino , ecc., Non posso assumere la window .

A quanto ho capito, questo non funziona in ES 5 con "use strict" ;

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

Questo fallirà anche con un’eccezione generata

 var MyGLOBAL = window || GLOBAL 

Quindi sembra che mi sia rimasto

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

Nessuno di questi casi passerà a JSLint.

Mi sto perdendo qualcosa?

Bene, puoi usare l’operatore typeof , e se l’identificatore non esiste in nessun punto della catena dell’ambito, non genererà un ReferenceError , ritornerà semplicemente "undefined" :

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

Ricorda inoltre che this valore su Global code fa riferimento all’object globale, il che significa che se l’istruzione if è nel contesto globale, puoi semplicemente controllare this.ModuleName .

Informazioni su (function () { return this; }()); tecnica, hai ragione, in modalità rigorosa this valore sarà semplicemente undefined .

In modalità rigorosa ci sono due modi per ottenere un riferimento all’object Global, indipendentemente da dove ti trovi:

  • Attraverso il costruttore Function :

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

Le funzioni create con il costruttore Function non ereditano la rigidità del chiamante, sono severe solo se avviano il loro corpo con la direttiva 'use strict' , altrimenti non sono rigide.

Questo metodo è compatibile con qualsiasi implementazione ES3.

  • Attraverso una chiamata eval indiretta , ad esempio:

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

Quanto sopra funzionerà perché in ES5, le chiamate indirette a eval , utilizzano l’ ambiente globale come entrambi, l’ambiente variabile e l’ambiente lessicale per il codice eval.

Vedere i dettagli su Immissione del codice di prova , Passaggio 1.

Ma sappiate che l’ultima soluzione non funzionerà con le implementazioni ES3, perché una chiamata indiretta a eval su ES3 utilizzerà gli ambienti variabili e lessicali del chiamante come gli ambienti per il codice eval stesso.

E alla fine, potresti trovare utile rilevare se la modalità rigorosa è supportata:

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

Soluzione pazzesca su una linea:

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

.

.

.

Lavori

  • in ogni ambiente (che ho provato)
  • in modalità rigorosa
  • e anche in uno scope nidificato

Aggiornamento 2014-Sept-23

Questo può ora fallire se le intestazioni HTTP negli ultimi browser vietano esplicitamente la valutazione.

Una soluzione alternativa sarebbe provare / catturare la soluzione originale in quanto solo i browser sono noti per eseguire questo tipo di sottoinsieme di JavaScript.

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

“ `

Esempio:

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

Provato:

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

Perché:

In breve: è una stranezza strana. Vedi i commenti qui sotto (o il post in alto)

In strict mode this non è mai globale, ma anche in strict mode eval opera in un contesto separato in cui this è sempre globale.

In modalità non rigida, this è il contesto attuale. Se non esiste un contesto attuale, assume il globale. Una funzione anonima non ha contesto e quindi in modalità non rigida assume il globale.

Sub Rant:

C’è una sciocca disfunzione di JavaScript che il 99,9% delle volte confonde semplicemente le persone chiamate “operatore virgola”.

 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 

Perché non usare semplicemente questo in un ambito globale come parametro per una funzione wrapper, come segue?

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

Ecco qui 🙂

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

Questo dovrebbe funzionare ovunque, ad esempio da un’altra chiusura.

Modifica: leggi il tuo post più attentamente e leggi la parte relativa alla modalità rigorosa ES5. Qualcuno può far luce su questo? Questo è stato il modo accettato per ottenere l’object globale per tutto il tempo che posso ricordare … Spero davvero che non finisca per rompersi.

Modifica 2 – La risposta di CMS ha più informazioni sulla modalità rigorosa di ES5 in this .

Penso che questo sia abbastanza ok in rhino, node, browser e con jslint (senza ulteriori indicatori di soluzione alternativa) – questo sarebbe d’aiuto? Mi sto perdendo qualcosa?

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

Sebbene io stesso tenda ad usare l’object window e se ho bisogno di test headless posso usare env.js (rhino) o Phantom (node).

Ho avuto questo problema prima, non sono felice con la soluzione, ma funziona e passa JSLint (si presuma browser | assume nodo):

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

una volta che hai GLOBAL var puoi fare il tuo controllo e alla fine del tipo di script

 delete GLOBAL.GLOBAL; 

Questo non sta passando jslint: var Fn = Function, global = Fn('return this')();

Provalo tu stesso: http://www.jslint.com/

questo sarà: var Fn = Function, global = new Fn('return this')();

Ma effettivamente quelli sono la stessa cosa secondo MDN :

Invocare il costruttore Function come una funzione (senza utilizzare il nuovo operatore) ha lo stesso effetto che invocarlo come costruttore.

Ecco cosa sto usando:

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

Questa soluzione seguente funziona in:

  • Cromo
  • Node.JS
  • Firefox
  • MSIE
  • Operatori Web

Il codice è:

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

Hai solo bisogno di cambiare X per il nome della variabile che desideri