Подтвердить что ты не робот

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

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

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

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

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

4b9b3361

Ответ 1

Ответ Harmen неплохой, но позвольте мне подробно рассказать, где это делается компилятором 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 in foo.coffee и x in 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 просто заботится о это для вас.

Ответ 2

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

(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

Ответ 3

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

(function() {

}());

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

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

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

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

       }
    }

    return _self;
}());

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