2012-03-09 19 views
20

Qual è il modo consigliato per ottenere un handle per in modalità rigorosa ES5 in un ambiente host sconosciuto?Ottenere un riferimento all'oggetto globale in un ambiente sconosciuto in modalità rigorosa

ECMAScript non fornisce un modo integrato per fare riferimento all'oggetto globale di cui sono a conoscenza. Se lo fa, questa è la risposta che sto cercando.

In un ambiente noto, l'oggetto globale di solito ha una proprietà autoreferenziale. Poiché l'oggetto globale è il VO per l'ambito globale, proprietà dell'oggetto globale sono variabili globali, in modo che possiamo utilizzare ottenere un handle all'oggetto globale da qualsiasi luogo:

  • In un browser web, possiamo utilizzare window o self.

  • In node.js, è possibile utilizzare global.

Tuttavia, questo non è necessariamente il caso in tutti gli ambienti host. Per quanto ne so, Windows Script Host non fornisce alcun modo per accedere all'oggetto globale. Il modo consigliato per ottenere l'oggetto globale in WSH sembra essere quello di utilizzare la parola chiave this in un contesto in cui non si risolve in un oggetto. Ad esempio:

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

Questa tecnica funziona per qualsiasi ambiente host, ma non in modo rigoroso, perché un indefinito this non riferimento all'oggetto globale strict mode:

Se questo viene valutata entro rigorosa codice di modalità, quindi questo valore non è forzato a un oggetto. Un valore null o undefined non viene convertito nell'oggetto globale e i valori primitivi non vengono convertiti in oggetti wrapper. Il valore passato tramite una chiamata di funzione (comprese le chiamate effettuate usando Function.prototype.apply e Function.prototype.call) non costringe il valore passato a questo oggetto (10.4.3, 11.1.1, 15.3.4.3, 15.3. 4.4).

Come previsto, il codice seguente genera undefined:

(function(){ 
    "use strict"; 
    var GLOBAL = (function(){return this}()); 
    console.log(GLOBAL); 
}()); 

Quindi, qual è il modo corretto di ottenere un handle all'oggetto globale in qualsiasi ambiente, indipendentemente dalla modalità rigorosa?

A proposito, il mio approccio attuale è a fiutare per le variabili globali riferimento all'oggetto globale come questo:

var self, window, global = global || window || self; 

... e poi basta usare global. Penso che questa sia una cattiva soluzione per una serie di motivi, molti dei quali sono abbastanza ovvi, e non affronta il problema WSH.

+1

non potresti fare "uso rigoroso"; (function (global) {}) (this) '? (Non ho provato questo qualunque). – Marshall

+0

Che funziona in Node.js, almeno, @Marshall –

+0

@DavidEllis woops, questa è la mia piattaforma di scelta O_o Credo che dovrei controllarlo in altri prima di dire nulla;) – Marshall

risposta

29

In ES5, è possibile ottenere un riferimento all'oggetto globale dall'interno modalità rigorosa tramite chiamata eval indiretta:

"use strict"; 
var global = (1,eval)('this'); 

Date un'occhiata a my article; particolarmente a questo section on strict mode.

+0

grazie per la risposta, ho letto molti dei tuoi articoli (che sono eccellenti tra l'altro) ma devo aver perso questo. Ho pensato di usare 'eval', ma non sapevo di questo trucco indiretto (usando semplicemente 'eval' senza valutazione indiretta nello scope della funzione, ovviamente). –

+0

Grazie per le parole gentili :) A proposito di trucco eval, ho sentito qualcosa su Node.js che non segue il comportamento di ES5 a tale riguardo e che ci sono altre magie dietro le quinte. Non ho mai avuto la possibilità di testarlo, quindi potresti voler controllare due volte. Funziona in tutti i browser che ho mai provato, tuttavia, e dovrebbe funzionare in teoria, poiché è così che è specificato in ES5. – kangax

+0

Lo verificherò nel nodo ... se è rotto nel nodo, posso semplicemente farlo controllare un 'global' già esistente per ovviare a questo (e rinominare' global' nell'esempio in qualcos'altro non oscurerà il 'global' esistente se chiamato dallo scope della funzione). Questo è esattamente quello che stavo cercando, grazie. –

1

In modalità rigorosa, il modo per ottenere un riferimento all'oggetto globale è assegnare una variabile nell'oggetto globale che fa riferimento a se stesso.

Cioè this means the global object when in the global context, quindi la soluzione è semplice:

"use strict"; 
var global = global || this; 
(function() { global.hello = "world"; })(); 
console.log(hello); // Outputs 'world' as expected 

Questo vuol significa che si deve inquinare il namespace globale con un riferimento a se stessa, ma, come si dice, ma dovrebbe essere già stato Là.

+0

Attendi, il riferimento a 'global' fallirà se non utilizzi un controllo' typeof'? –

+2

@wilmoore: No, perché l'istruzione 'var' viene issata. 'var global = global || questo; 'è efficacemente elaborato come' var global; globale = globale || questo; '.Se 'global' esiste già,' var global' è un no-op, altrimenti viene creato con un valore iniziale di 'undefined', che viene poi sovrascritto nella prossima istruzione. –

+0

Sì, quando ho pubblicato originariamente, sapevo che il sollevamento di 'var', ma per essere onesto, non l'ho messo insieme in questo particolare contesto. Grazie per il testa a testa :) –

7

In global code, thisBinding è impostato sull'oggetto globale indipendentemente dalla modalità rigorosa. Ciò significa che puoi passare da lì al tuo modulo IEFE:

// "use strict"; or not 
(function(global) { 
    "use strict"; 
    … 
    console.log(global); 
    … 
}(this)); 
+0

In realtà è simile alla risposta di @DavidEllis, ma senza inquinare l'ambito globale :-) – Bergi