Come si definiscono le variabili globali in CoffeeScript?

Su Coffeescript.org:

bawbag = (x, y) -> z = (x * y) bawbag(5, 10) 

compilerebbe a:

 var bawbag; bawbag = function(x, y) { var z; return (z = (x * y)); }; bawbag(5, 10); 

la compilazione tramite coffee-script sotto node.js esegue il wrapping in questo modo:

 (function() { var bawbag; bawbag = function(x, y) { var z; return (z = (x * y)); }; bawbag(5, 10); }).call(this); 

I documenti dicono:

Se desideri creare variabili di primo livello per altri script da utilizzare, allegarli come proprietà sulla finestra o sull’object export in CommonJS. L’operatore esistenziale (indicato di seguito), ti offre un modo affidabile per capire dove aggiungerli, se hai come target sia CommonJS che il browser: root = exports? Questo

Come definire variabili globali quindi in CoffeeScript. Cosa significa “collegarli come proprietà sulla finestra”?

Poiché lo script coffee non ha istruzioni var , lo inserisce automaticamente per tutte le variabili nel coffee-script, in questo modo impedisce alla versione JavaScript compilata di filtrare tutto nello spazio dei nomi globale .

Quindi, dato che non c’è modo di creare qualcosa di “fuga” nello spazio dei nomi globale dal lato delle cose del coffee-script, è necessario definire le variabili globali come proprietà dell’object globale .

collegali come proprietà sulla finestra

Ciò significa che devi fare qualcosa come window.foo = 'baz'; , che gestisce il caso del browser, dal momento che l’ object globale è la window .

Node.js

In Node.js non ci sono oggetti window , ma c’è l’object exports che viene passato nel wrapper che avvolge il modulo Node.js (vedi: https://github.com/ry/node/blob/master/src/node. js # L321 ), quindi in Node.js quello che dovresti fare è exports.foo = 'baz'; .

Ora diamo un’occhiata a ciò che afferma nella tua citazione dai documenti:

… indirizzando sia CommonJS che il browser: root = exports? Questo

Questo è ovviamente un copione del caffè, quindi diamo un’occhiata a ciò che questo in realtà compila:

 var root; root = (typeof exports !== "undefined" && exports !== null) ? exports : this; 

Innanzitutto controllerà se le exports sono definite, poiché provare a fare riferimento a una variabile inesistente in JavaScript produrrebbe altrimenti un SyntaxError (tranne quando è usato con typeof )

Quindi, se esiste exports , come nel caso di Node.js (o in un sito Web scritto male …), la directory punta a exports , altrimenti a this . Quindi cos’è this ?

 (function() {...}).call(this); 

Usando .call su una funzione legheremo this all’interno della funzione al primo parametro passato, nel caso del browser this sarebbe ora l’object window , nel caso di Node.js sarebbe il contesto globale che è anche disponibile come object global .

Ma dal momento che si ha la funzione require in Node.js, non è necessario assegnare qualcosa all’object global in Node.js, ma si assegna all’object exports che viene poi restituito dalla funzione require .

Coffee-Script

Dopo tutta questa spiegazione, ecco cosa devi fare:

 root = exports ? this root.foo = -> 'Hello World' 

Questo dichiarerà la nostra funzione foo nel namespace globale (qualunque cosa accada).
È tutto 🙂

A me sembra che @atomicules abbia la risposta più semplice, ma penso che possa essere semplificata un po ‘di più. Devi mettere un @ prima di tutto ciò che vuoi essere globale, in modo che si this.anything a this.anything e this riferisce all’object globale.

così…

 @bawbag = (x, y) -> z = (x * y) bawbag(5, 10) 

compila per …

 this.bawbag = function(x, y) { var z; return z = x * y; }; bawbag(5, 10); 

e funziona all’interno e all’esterno del wrapper dato da node.js

 (function() { this.bawbag = function(x, y) { var z; return z = x * y; }; console.log(bawbag(5,13)) // works here }).call(this); console.log(bawbag(5,11)) // works here 

Ivo l’ha inchiodato, ma dirò che c’è un trucco sporco che puoi usare, anche se non lo consiglio se stai andando per i punti stile: puoi incorporare il codice JavaScript direttamente nel tuo CoffeeScript evadendolo con i backtick.

Tuttavia, ecco perché questa è solitamente una ctriggers idea: il compilatore CoffeeScript non è a conoscenza di tali variabili, il che significa che non obbediranno alle normali regole di scope di CoffeeScript. Così,

 `foo = 'bar'` foo = 'something else' 

compila a

 foo = 'bar'; var foo = 'something else'; 

e ora hai te stesso due foo in ambiti diversi. Non c’è modo di modificare il foo globale dal codice CoffeeScript senza fare riferimento all’object globale, come descritto da Ivy.

Naturalmente, questo è solo un problema se si effettua un assegnamento a foo in CoffeeScript – se foo diventa di sola lettura dopo aver ricevuto il suo valore iniziale (cioè è una costante globale), allora l’approccio della soluzione JavaScript incorporato potrebbe essere un po ‘accettabile ( sebbene ancora non raccomandato).

È ansible passare l’opzione -b quando si compila il codice tramite coffee-script sotto node.js. Il codice compilato sarà lo stesso di su coffeescript.org.

Aggiungere alla risposta di Ivo Wetzel

Sembra esserci una syntax abbreviata per le exports ? this exports ? this che posso trovare solo documentato / menzionato su un post di gruppo di Google .

Cioè in una pagina web per rendere globalmente disponibile una funzione, dichiari nuovamente la funzione con un prefisso @ :

  Click me! 

Penso che quello che stai cercando di ottenere possa essere fatto semplicemente in questo modo:

Mentre stai compilando il coffeescript, usa il parametro “-b”.

-b / --bare Compila il codice JavaScript senza il wrapper di sicurezza della funzione di primo livello.

Quindi qualcosa di simile: coffee -b --compile somefile.coffee whatever.js

Questo produrrà il tuo codice come nel sito CoffeeScript.org.

Se sei una persona ctriggers (io sono una persona ctriggers.), Puoi ottenere semplicemente questo: (->@)()

Come in,

 (->@)().im_a_terrible_programmer = yes console.log im_a_terrible_programmer 

Funziona, perché quando si richiama un Reference a una Function ‘nuda’ (cioè, func() , invece di new func() o obj.func() ), qualcosa viene comunemente chiamato ‘modello di chiamata-chiamata’, associa sempre this all’object globale per quel contesto di esecuzione .

The CoffeeScript sopra semplicemente compila a (function(){ return this })() ; quindi stiamo esercitando tale comportamento per accedere in modo affidabile all’object globale.

Dal momento che il coffeescript viene usato raramente, è ansible utilizzare global variabile global fornita da node.js o browserify (e qualsiasi discendente come coffeeify, gulp build scripts, ecc.).

In node.js global è lo spazio dei nomi globale.

In browserify global è uguale alla window .

Quindi:

 somefunc = -> global.variable = 123