Что случилось с этим шаблоном JavaScript? - PullRequest
27 голосов
/ 14 мая 2011

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

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

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

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

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

Ответы [ 7 ]

17 голосов
/ 14 мая 2011

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

Например, вот довольно стандартный паттерн:

Money = (function() {
    var someCompletelyPrivateVariable;

    function doSomethingCompletelyPrivate() {
    }

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

    return Money;
})();

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

15 голосов
/ 14 мая 2011

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

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

... CoffeeScript сгенерирует следующее, что в основном идентично ответу @TJ Crowder:

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

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

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

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


РЕДАКТИРОВАТЬ:

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

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 таким, какой он есть (особенно с новыми и предстоящими изменениями).

4 голосов
/ 17 мая 2011

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

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

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

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

2 голосов
/ 15 мая 2011
Money = (function() {
    var uid = 0;
    function Money(rawString) {
        this.cents = this.parseCents(rawString);
        this.uid = uid++;
    }
    return Money;
})();

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

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

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

2 голосов
/ 14 мая 2011

Это не похоже на реальный пример, оператор группировки «внешней» функции не имеет смысла, и, как говорит ТДЖ, он абсолютно ничего не делает. Вызванный как конструктор, он вернет пустой объект.

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

1 голос
/ 14 мая 2011

Здесь происходит три вещи:

Во-первых, как отметили другие авторы, код, приведенный в скриншоте 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) и другими браузерами <em>, если не ограничен областью действия в таком модуле (см. CoffeeScript FAQ , заголовок " Есть ли способ назвать функции для рефлексии и рекурсии? "). Поэтому вторичное использование синтаксиса class заключается в безопасном объявлении именованных функций.

Надеюсь, это ответит на ваш вопрос, Шиме.

0 голосов
/ 14 мая 2011

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...