При создании классов в coffeescript существует ли когда-либо причина не использовать жирную стрелку для методов экземпляра?

Когда вы создаете классы в coffeescript, существует ли когда-либо причина для не использовать тучную стрелку для методов экземпляра?

Изменить: Хорошо, тогда! Отличный ответ!:)
Подводя итог, возникают следующие проблемы:
- Делает больше памяти
- Невозможность запланировать
- Запрашивает вопрос, почему он используется для этого метода?
Конвенция:
- Быть явным при связывании функций.
- Объявить методы с жирными стрелками в конструкторе.
- Используйте столько, сколько хотите, просто не в объявлениях классов.

Ответ 1

Да, есть причины не использовать жирные стрелки всегда. На самом деле я бы утвердил, что никогда не использовал методы с жирными стрелками:)

Методы тонкой стрелки и жирной стрелки концептуально разные. Первые компилируются в ожидаемый код JS на основе прототипов; методы принадлежат прототипу класса. С другой стороны, методы со стрелками со стрелками связаны с каждым экземпляром кода конструктора.

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

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

class Foo
  # Using fat-arrow method
  bar: (x) => alert x

# I have some Foos
foos = (new Foo for i in [1..3])

# And i want to path the bar method to add some logging. 
# This might be in another module or file entirely.
oldbar = Foo::bar
Foo::bar = (args...) ->
  console.log "Foo::bar called with", args
  oldbar.apply @, args

# The console.log will never be called here because the bar method 
# has already been bound to each instance and was not modified by 
# the above patch.
foo.bar(i) for foo, i in foos

Но самый важный недостаток, на мой взгляд, более субъективен: введение методов толстой стрелки делает код (и язык) излишне непоследовательным и трудным для понимания.

Код становится более непоследовательным, потому что перед тем, как вводить методы толстой стрелки в любое время, когда мы видим <someProp>: <someVal> в определении класса, мы знаем, что это означает "объявить свойство с именем <someProp> со значением <someVal> в прототипе класса" (если <someProp> == 'constructor', что является особым случаем), не имеет значения, является ли <someVal> числом или функцией, это будет просто свойство в прототипе. С внедрением методов с жирными стрелками у нас теперь есть еще один ненужный частный случай: если <someVal> - функция с жирными стрелками, это будет совершенно иначе, чем с любым другим значением.

И там другая несогласованность: жирные стрелки по-разному связывают this, когда они используются в определении метода, чем при использовании где-либо еще. Вместо сохранения внешнего this (который внутри a class, this привязан к конструктору класса) this внутри метода с жирными стрелками является объектом, который не существует, когда метод определен ( т.е. экземпляр класса).

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


При всем этом я бы рекомендовал никогда не использовать методы толстой стрелки. Предпочитаете привязать метод к экземпляру, где он будет использоваться вместо того, где объявлен метод. Например:

# Be explicit about 'onClick' being called on 'someObject':
$someJQueryElement.on 'click', (e) -> someObject.onClick e

# Instead of:
$someJQueryElement.on 'click', someObject.onClick

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

# Instead of fat-arrow methods:
class A
  constructor: ->
    @bar = 42
  foo: => 
    console.log @bar

# Assing the method in the constructor, just like you would 
# do with any other own property
class A
  constructor: ->
    @bar = 42
    @foo = => 
      console.log @bar

Я думаю, что во втором определении class A это гораздо более явное, что происходит с методом foo, чем в первом определении.

Наконец, обратите внимание, что я не спорю против использования толстой стрелки вообще. Это очень полезная конструкция, и я все время использую ее для обычных функций; я просто предпочитаю избегать использования его внутри определения метода class:)


Изменить. Еще один случай против использования методов с жирными стрелками: функции декоратора:

# A decorator function to profile another function.
profiled = (fn) ->
  (args...) ->
    console.profile()
    fn.apply @, args
    console.profileEnd()

class A
  bar: 10

  # This works as expected
  foo: profiled (baz) ->
    console.log "@bar + baz:", @bar + baz

  # This doesn't
  fatArrowedFoo: profiled (baz) =>
    console.log "@bar + baz:", @bar + baz

(new A).foo 5           # -> @bar + baz: 15
(new A).fatArrowedFoo 5 # -> @bar + baz: NaN

Ответ 2

Позвольте мне добавить альтернативное представление.

Разработанные причины, высказанные @epidemian для избежания жирной стрелки, хорошо и хорошо, но учтите следующее:

  • если вам все равно (много или вообще) о "базовом JS-коде на основе прототипа", создаваемом CoffeeScript, поскольку вы можете писать согласованный и без ошибок код CoffeeScript;
  • если вы не планируете писать gazillion крошечные классы ala Java, которые будут тратить 99% своего времени на вызов друг друга методами вверх и вниз по дереву наследования и получить небольшую работу в этом процессе; сказал другой путь, если вы признаете, что "внутренние петли", чувствительные к производительности, не являются хорошим местом для вызова методов вызова;
  • если вы не планируете декорировать, обезглавливать или иным образом модифицировать методы своих классов во время выполнения;
  • если вы укажете свое использование толстой стрелки в комментарии к заголовку, для будущих разработчиков, работающих над вашим кодом;

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

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

Более формально, толстая стрелка делает ключевое слово this (и его сокращенное @) полностью лексически охваченным, как и любой другой идентификатор. История языка программирования показывает, что лексическое охват является наиболее интуитивно понятным и менее подверженным ошибкам способом для идентификаторов областей. Вот почему он стал стандартным поведением для всех новых языков давным-давно.

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

NB: у CoffeeScript 1.6.1 есть ошибка, связанная с методами стрельбы с жирами, поэтому вам следует избегать этого. Предыдущие и более поздние версии должны быть в порядке.

Производительность

При использовании в качестве обычной (анонимной) функции жирная стрелка не добавляет никаких накладных расходов. В объявлениях методов он добавляет крошечные операционные и операционные ресурсы процессора (действительно крошечный: несколько наносекунд и несколько байт ОЗУ для каждого вызова метода, и последний исчезает на двигателях с оптимизацией хвостового вызова.)

ИМХО Ясная ясность и безопасность жира, выраженная в обмене, является достаточным основанием для терпимости и даже приветствовать небольшие накладные расходы. Многие другие идиомы CoffeeScript добавляют свои собственные крошечные накладные расходы к сгенерированному коду (для циклов и т.д.), Чтобы сделать поведение языка более последовательным и менее подверженным ошибкам. Жирная стрелка ничем не отличается.