tutorial javascript node.js coffeescript

tutorial - coffeescript vs javascript



Patrón para módulos de CoffeeScript (3)

Esta es una sintaxis similar a esto:

(function() { }());

que se llama una función inmediata. la función se define y ejecuta de inmediato. La ventaja de esto es que puede colocar todo su código dentro de este bloque y asignar la función a una única variable global, reduciendo así la contaminación global del espacio de nombres. proporciona un buen alcance contenido dentro de la función.

Este es el patrón típico que uso al escribir un módulo:

var MY_MODULE = (function() { //local variables var variable1, variable2, _self = {}, etc // public API _self = { someMethod: function () { } } return _self; }());

no estoy seguro de cuáles podrían ser exactamente las contras, si alguien más sabe de alguna, me complacería conocerlas.

Al revisar el código fuente de CoffeeScript en Github , noté que la mayoría, si no todos, de los módulos se definen de la siguiente manera:

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

Este patrón parece que envuelve todo el módulo en una función anónima y se llama a sí mismo.

¿Cuáles son los pros (y los contras) de este enfoque? ¿Hay otras maneras de lograr los mismos objetivos?


La respuesta de Harmen es bastante buena, pero permítanme que explique un poco sobre dónde lo hace el compilador de CoffeeScript y por qué.

Cuando compilas algo con coffee -c foo.coffee , siempre obtienes un foo.js que se ve así:

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

¿Porqué es eso? Bueno, supongamos que pones una tarea como

x = ''stringy string''

en foo.coffee . Cuando ve eso, el compilador pregunta: ¿ x ya existe en este ámbito o en un ámbito externo? Si no, pone una declaración var x en la parte superior de ese alcance en el resultado de JavaScript.

Ahora supongamos que escribes

x = 42

en bar.coffee , compilar ambos y concatenar foo.js con bar.js para el despliegue. Obtendrás

(function() { var x; x = ''stringy string''; ... }).call(this); (function() { var x; x = 42; ... }).call(this);

Entonces, la x en foo.coffee y la x en bar.coffee están totalmente aisladas la una de la otra. Esta es una parte importante de CoffeeScript: las variables nunca se filtran de un archivo .coffee a otro a menos que se exporten explícitamente (al adjuntarse a un global compartido, o a exports en Node.js).

Puede anular esto usando la bandera -b ("bare") para coffee , pero esto solo debe usarse en casos muy especiales. Si lo usaste con el ejemplo anterior, la salida que obtendrías sería

var x; x = ''stringy string''; ... var x; x = 42; ...

Esto podría tener consecuencias nefastas. Para probarlo usted mismo, intente agregar setTimeout (-> alert x), 1 en foo.coffee . Y tenga en cuenta que no tiene que concatenar los dos archivos JS usted mismo: si usa dos etiquetas separadas <script> para incluirlas en una página, todavía se ejecutan efectivamente como un solo archivo.

Al aislar los ámbitos de diferentes módulos, el compilador de CoffeeScript lo salva del dolor de cabeza de preocuparse de si los diferentes archivos en su proyecto pueden usar los mismos nombres de variable local. Esta es una práctica común en el mundo de JavaScript (ver, por ejemplo, la fuente de jQuery , o casi cualquier plugin jQuery) -CoffeeScript solo se encarga de eso.


Lo bueno de este enfoque es que crea variables privadas, por lo que no habrá ningún conflicto con los nombres de las variables:

(function() { var privateVar = ''test''; alert(privateVar); // test })(); alert(typeof privateVar); // undefined

La adición de .call(this) hace que this palabra clave haga referencia al mismo valor al que se refiere fuera de la función. Si no se agrega, la palabra clave se referirá automáticamente al objeto global.

Un pequeño ejemplo para mostrar la diferencia sigue:

function coffee(){ this.val = ''test''; this.module = (function(){ return this.val; }).call(this); } var instance = new coffee(); alert(instance.module); // test function coffee(){ this.val = ''test''; this.module = (function(){ return this.val; })(); } var instance = new coffee(); alert(typeof instance.module); // undefined