Шаблон для модулей CoffeeScript

Просматривая исходный код CoffeeScript на Github, я заметил, что большинство, если не все, модулей определены следующим образом:

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

Этот шаблон выглядит так, как будто он оборачивает весь модуль в анонимную функцию и вызывает сам себя.

Каковы плюсы (и минусы) этого подхода? Есть ли другие способы достижения тех же целей?

3 ответа

Решение

Ответ Хармена довольно хороший, но позвольте мне немного рассказать о том, где это делается компилятором CoffeeScript и почему.

Когда вы что-то компилируете с coffee -c foo.coffee, вы всегда получите foo.js это выглядит так:

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

Это почему? Ну, предположим, вы поставили задание как

x = 'stringy string'

в foo.coffee, Когда он видит это, компилятор спрашивает: x уже существует в этой области или внешней области? Если нет, это ставит var x объявление в верхней части этой области в выводе JavaScript.

Теперь предположим, что вы пишете

x = 42

в bar.coffee, скомпилировать оба и объединить foo.js с bar.js для развертывания. Ты получишь

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

Итак x в foo.coffee и x в bar.coffee полностью изолированы друг от друга. Это важная часть CoffeeScript: переменные никогда не просачиваются из одного файла.coffee в другой, если они явно не экспортированы (будучи прикрепленными к общему глобальному или exports в Node.js).

Вы можете изменить это, используя -b ("голый") флаг coffee, но это следует использовать только в очень особых случаях. Если бы вы использовали его в приведенном выше примере, вы получите результат:

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

Это может иметь ужасные последствия. Чтобы проверить это самостоятельно, попробуйте добавить setTimeout (-> alert x), 1 в foo.coffee, И обратите внимание, что вам не нужно объединять два файла JS самостоятельно - если вы используете два отдельных <script> теги, чтобы включить их на странице, они по-прежнему эффективно работают как один файл.

Изолируя области действия различных модулей, компилятор CoffeeScript избавляет вас от головной боли от беспокойства о том, могут ли разные файлы в вашем проекте использовать одни и те же имена локальных переменных. Это обычная практика в мире JavaScript (см., Например, исходный код jQuery или почти любой плагин jQuery) - CoffeeScript просто позаботится об этом за вас.

Хорошая вещь в этом подходе состоит в том, что он создает частные переменные, поэтому не будет никакого конфликта с именами переменных:

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

alert(typeof privateVar); // undefined

Добавление .call(this) делает this Ключевое слово ссылается на то же значение, что и вне функции. Если он не добавлен, this Ключевое слово будет автоматически ссылаться на глобальный объект.

Вот небольшой пример, показывающий разницу:

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

Этот синтаксис похож на это:

(function() {

}());

которая называется непосредственной функцией. функция определяется и выполняется немедленно. Преимущества этого в том, что вы можете поместить весь свой код в этот блок и назначить функцию одной глобальной переменной, тем самым уменьшая загрязнение глобального пространства имен. это обеспечивает хороший ограниченный объем внутри функции.

Это типичный шаблон, который я использую при написании модуля:

var MY_MODULE = (function() {
    //local variables
    var variable1,
        variable2,
        _self = {},
        etc

    // public API
    _self = {
       someMethod: function () {

       }
    }

    return _self;
}());

не уверен, что за минусы могут быть точно, если кто-то еще знает о чем-либо, я был бы рад узнать о них.

Другие вопросы по тегам