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

Что с этим шаблоном JavaScript?

Я видел этот шаблон:

Money = (function() {
    function Money(rawString) {
        this.cents = this.parseCents(rawString);
    }
});

в этом предварительном просмотре скринкастов CoffeeScript. (Домашняя страница для скринкаста здесь.)

Теперь я не понимаю этот шаблон. Существует функция Money, содержащая функцию Money. Что это значит?

Может кто-нибудь объяснить?

4b9b3361

Ответ 1

Как указано, нет никакого смысла в этом шаблоне, кроме того, что внешний Money символ может быть удален из объекта window (кроме IE7 и ниже, но эта другая история), потому что это нормальное (неявное) свойство of window (в отличие от a var или символа, полученного из объявления функции). Но даже тогда внешний символ Money получает функцию, которая абсолютно ничего не делает. Может ли это быть неверно указано?

Например, здесь достаточно стандартный шаблон:

Money = (function() {
    var someCompletelyPrivateVariable;

    function doSomethingCompletelyPrivate() {
    }

    function Money(rawString) {
        this.cents = this.parseCents(rawString);
    }

    return Money;
})();

Это шаблон модуля, и он позволяет иметь полностью частные переменные и функции (оба проиллюстрированные), имея только один общедоступный символ. Но мне нужно было отредактировать честный бит, чтобы создать это (наиболее значимые изменения - это return Money; в конце и добавление () после анонимной функции, поэтому мы вызываем его, а не просто определяем его.

Ответ 2

Использование кода CoffeeScript, который, по утверждению видео, является правильным преобразованием...

class Money
    constructor: (rawString) ->
        @cents = @parseCents rawString

... CoffeeScript генерирует следующее, которое в основном идентично @T.J. Ответ Краудера:

var Money;
Money = (function() {
  function Money(rawString) {
    this.cents = this.parseCents(rawString);
  }
  return Money;
})();

Я просто публикую это, чтобы показать, что на самом деле делает CoffeeScript, и что видео не отражает реальность.

Вы можете увидеть преобразование, если зайдите на сайт и нажмите кнопку "Try CoffeeScript".

Пожалуйста, не принимайте этот ответ.


EDIT:

Чтобы добавить использование частной переменной, которая использует область действия, вы можете сделать это:

class Money
    priv=0
    constructor: (rawString) ->
        @cents = @parseCents rawString
        @id = priv++

... который отображается как:

var Money;
Money = (function() {
  var priv;
  priv = 0;
  function Money(rawString) {
    this.cents = this.parseCents(rawString);
    this.id = priv++;
  }
  return Money;
})();

Кстати, я ничего не знаю о CoffeeScript. Его синтаксис выглядит запутанным для меня, но, возможно, только потому, что я не привык к нему.

Мне нравится JavaScript так, как он есть (особенно с новыми и еще предстоящими изменениями).

Ответ 3

Я автор упомянутого скринкаста и источник фрагмента. Несколько пояснений:

  • Контекст, в котором упоминался фрагмент, был в анимированном сравнении синтаксиса JavaScript и CoffeeScript.
  • Он был намеренно упрощен, чтобы не добавлять дополнительную путаницу в контексте концепции CoffeeScript, которую преподают в тот момент в видео (видео не пыталось преподавать конструктор JavaScript или синтаксис класса).
  • Вы можете получить полный текст JavaScript любого фрагмента CoffeeScript, запустив его через компилятор CoffeeScript, как показано на скринкасте, или запустив его на официальном веб-сайте CoffeeScript.

Я добавлю пояснения к видео и превью, упомянутым выше.

В противном случае другие объяснения здесь, касающиеся, являются правильными. Если вы строите класс JavaScript, вы должны вернуть текущий объект и вызвать анонимную функцию, показанную выше. Но это не пункт CoffeeScript.; -)

Ответ 4

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

@TJ - цитата правильная, вам нужно посмотреть около 40 секунд видео.

Ответ 5

Money = (function() {
    var uid = 0;
    function Money(rawString) {
        this.cents = this.parseCents(rawString);
        this.uid = uid++;
    }
    return Money;
})();

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

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

Другим вариантом для достижения этого будет использование Money.uid, но это будет общедоступно.

Ответ 6

Здесь три вещи:

Во-первых, как отмечали другие ответчики, код, указанный в скринкасте PeepCode и цитируемый в вопросе, имеет пару ошибок. Существует return, и вызывается внешняя функция.

Во-вторых, как T.J. отметил, что это шаблон модуля. Вы можете выполнить произвольный код в блоках CoffeeScript class, а переменные подчиняются тем же правилам определения, что и в других функциях. Так, например, вы можете написать

class HashedPassword
  salt = Math.random()
  constructor: (password) ->
    @value = hash password, salt

в этом случае salt отображается только в определении класса HashedPassword.

Наконец, следует отметить, что это единственное место, где CoffeeScript когда-либо использует "названные" функции (те, которые указаны с function foo(), а не foo = function()). Именованные функции отлично подходят для трассировки стека и т.д., Но они вызывают несогласованности между IE (< 9) и другими браузерами, если они не охвачены таким модулем (см. CoffeeScript FAQ, заголовок "Есть ли способ назвать функции, для отражения и рекурсии?" ). Поэтому вторичное использование синтаксиса class состоит в том, чтобы безопасно объявлять именованные функции.

Надеюсь, что ответ на ваш вопрос, Šime.

Ответ 7

Внешняя функция Money не принимает аргументов. Внутренняя функция Money захватывает rawString через закрытие. Преимущество здесь в том, что вы не загрязняете глобальное пространство имен внутренним определением функции Money.

EDIT: Я бы согласился с TJ, что шаблон в его нынешнем виде бесполезен. Он ничего не делает, и внешняя функция используется исключительно для определения области видимости. Не видя полного примера автора скринкаста, трудно сказать, куда он идет с этим.