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; })();
var global = Function('return this')() || (42, eval)('this');
.
.
.
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; }
“ `
(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'); }());
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:
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