2011-01-12 12 views
7

Dato il seguente codice CoffeeScript:Perché coffeescript genera classi come questa?

class Animal 
    constructor: (@name) -> 
    speak: (things) -> "My name is #{@name} and I like #{things}" 

Viene generato:

var Animal = (function() { 
    function Animal(name) { 
    this.name = name; 
    } 
    Animal.prototype.speak = function(things) { 
    return "My name is " + this.name + " and I like " + things; 
    }; 
    return Animal; 
})(); 

Ma perché non viene generato questo codice più idiomatica?

var Animal = function Animal(name) { 
    this.name = name; 
}; 
Animal.prototype.speak = function(things) { 
    return "My name is " + this.name + " and I like " + things; 
}; 

so che CoffeeScript avvolge un sacco di roba in funzioni anonime per controllare la portata delle perdite, ma ciò che potrebbe fuoriuscire qui?

+3

Un voto soggettivo e argomentativo vicino? Veramente? Questa è una domanda valida per chiedere perché è necessario avvolgere le funzioni in una funzione anonima. – ryeguy

risposta

12

Il codice generato consente di assegnare in modo affidabile funzioni con nome in Internet Explorer. (In questo caso, "Animale".) Se si utilizza semplicemente una funzione con nome in ambito superiore, sarà in conflitto con tutte le dichiarazioni var Animal = che potrebbero essere presenti ... anche in ambiti inferiori, impedendo loro di fare riferimento correttamente. Per ovviare al bug di IE, includiamo la funzione wrapper attorno alla definizione della classe.

+5

"Conflitto di nome" non è esattamente la preoccupazione (stai facendo 'var Animal =' comunque). Il problema è che non dovresti mai aver chiamato la funzione _expressions_ per JScript. Ulteriori informazioni su "il bug di IE": http://kangax.github.com/nfe/ – matyr

2

Questo serve per supportare i backtrace inclusi i nomi di classe e non solo i nomi di funzioni quando viene generata un'eccezione.

+0

Puoi elaborare? Non sono sicuro di capire come funziona. – casablanca

+0

@casablanca - consultare: http: //www.javascriptkata.it/2010/05/19/how-to-de-anonymize-your-anonymous-functions/È la differenza tra vedere 'aonon(), aonon()' e 'func1(), func2()' nella traccia dello stack . –

+0

@Sean: Questo spiega perché la funzione si chiama 'Animal', ma non sembra spiegare perché è racchiusa in una funzione anonima. – ryeguy

2

Il metodo CoffeeScript presenta anche vantaggi per la minificazione.

Da my other answer:

Per la maggior parte delle classi ragionevoli, la chiusura generata dal CoffeeScript genera uscita minimizzato minore. L'involucro chiusura è 25 byte di overhead minimizzato, ma si evita di ripetere il nome classe, risparmiando k * N byte (k = lettere-in-nome, N = num-di-ref). ad esempio, se una classe come BoilerPlateThingyFactory ha 2+ metodi, il wrapper di chiusura genera un codice minisito più piccolo.



più in dettaglio ...

The Coffee Codice generato usando una chiusura a minifies:

// Uglify '1.js' = 138 bytes (197 w/ whitespace): 

var Animal=function(){function e(e){this.name=e}return e.prototype.speak=function(e){return"My name is "+this.name+" and I like "+e},e}(); 

// with whitespace ("uglifyjs -b"): 

var Animal = function() { 
    function e(e) { 
     this.name = e; 
    } 
    return e.prototype.speak = function(e) { 
     return "My name is " + this.name + " and I like " + e; 
    }, e; 
}(); 

alternative di ryeguy "idiomatiche" minifies implementazione a questo :

// Uglify '2.js' = 119 bytes (150 w/ whitespace): 

var Animal=function(t){this.name=t};Animal.prototype.speak=function(e){return"My name is "+this.name+" and I like "+e}; 

// with whitespace ("uglifyjs -b"): 

var Animal = function(t) { 
    this.name = t; 
}; 

Animal.prototype.speak = function(e) { 
    return "My name is " + this.name + " and I like " + e; 
}; 

Nota come il nome "Animale" esista esattamente una volta nella forma Caffè e N = 2 volte nella varietà "idiomatica" di Ryeguy. Ora "Animale" ha solo 6 lettere, e c'è solo 1 metodo, quindi Coffee qui dovrebbe perdere di 25-6 = 19 byte. Consultando il mio codice miniato, è 138 byte a 119 byte, per un delta di ... 19 byte. Aggiungi altri 4 metodi e il vantaggio passerà a Coffee. E non sono solo i metodi; anche le costanti di classe e altri tipi di ref.

+0

L'espressione 'return' separata da virgole nel tuo codice uglificato è interessante. Nella mia console, 'return x, y, z;' sembra valutare tutte e tre le espressioni, ma restituisce solo l'ultima. C'è qualche effetto nel farlo in questo modo, oltre a rendere il codice più "brutto"? –

+0

@JustinMorgan - Lei ha scoperto l'operatore "virgola"! È come un punto e virgola, ma più potente in quanto può essere usato come espressione. quindi "a, b, c;" valuterà "a", quindi "b", quindi "c" e l'espressione generale avrà il valore da "c". È un operatore che JS eredita da C, fww. http://en.wikipedia.org/wiki/Comma_operator –

Problemi correlati