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

При построении классов в coffeescript, всегда ли есть причинане использовать жирную стрелку, например, методы?

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

 Thilo03 дек. 2012 г., 13:13
может быть полезно:stackoverflow.com/questions/8965855/...
 Thilo03 дек. 2012 г., 13:13
не использовать жирную стрелку, когда вам не нужно, она легче. Не уверен, если это имеет большое значение, хотя.
 davidpfahler03 дек. 2012 г., 14:45
Да. Также это позволяет избежать непредвиденных последствий. Вы всегда должны знать, почему вы добавляете что-то к поведению по умолчанию. Позже в вашем проекте вы не будете помнить, что все связано с помощью жирной стрелки, и вы будете преследовать ошибки, которые иначе никогда бы не произошли.
 robkuz03 дек. 2012 г., 15:34
также иногда может быть полезно использовать экземпляр в качестве объекта замыкания и передать метод в качестве обратного вызова другому методу.
 Simon Landeholm03 дек. 2012 г., 13:21
Так что это просто вопрос производительности?

Ответы на вопрос(2)

Решение Вопроса

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

Методы тонких стрелок и толстых стрелок - концептуально разные вещи. Первые компилируются в ожидаемый 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's patch.
foo.bar(i) for foo, i in foos

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

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

И есть еще одно несоответствие: толстые стрелкисвязатьthis иначе когда они используются в определении метода, чем когда-либо еще. Вместо сохранения внешнегоthis (который внутри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
 Simon Landeholm04 дек. 2012 г., 16:17
Хорошо, не ожидал такого сложного ответа! Буду читать позже ...
 epidemian06 дек. 2012 г., 14:30
@SimonLandeholm, я вижу в них разные проблемы. В случае с декоратором жирная стрелка не делает то, что ожидается: вместо привязкиthis с созданным экземпляром, он связывает его с конструктором класса (то же самое происходит, если вы простодобавить скобки вокруг функции жирной стрелки). Невозможность исправления является следствием нарушения предположения о том, чтоthis метода лениво связан (например,[].slice.call(arguments) является обычной конструкцией JS, которая опирается на это предположение)
 epidemian17 сент. 2014 г., 15:32
@ Goran_Mandic, вы можете использовать декораторы для методов, если высвязать их на конструкторе, Внутри конструктораthis будетA например, неA сам. Но в рамках определения класса,this являетсяAи у Coffee нет возможности узнать, что жирная стрелка функционирует в некотором произвольном выражении (т.е.profiled (baz) -> ...) на самом деле предназначен для привязки кA экземпляры вместоA сам. Надеюсь, это имеет смысл: P
 Simon Landeholm06 дек. 2012 г., 12:18
Что касается проблемы декоратора, разве это не та же самая проблема, что и неспособность исправить?
 programstinator17 сент. 2014 г., 14:55
@epidemian отличный ответ! Есть ли способ получить доступ к свойствам класса изнутри жирных стрелочных функций? я вижу это@bar не определено в вашемfatArrowedFoo функция. Наверное, я спрашиваю, как можно съесть мой торт и съесть его тоже :)

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

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

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

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

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

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

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

Представление

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

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

 owensmartin23 июн. 2014 г., 20:25
Спасибо за этот ответ. На самом деле я делаю именно это в веб-приложении, которое я пишу. В частности, Express ожидает функцию, которая принимает(req, res, next) в качестве параметров, а затем вы должны удерживать эти объекты во время обработки. Учитывая, что большая часть того, что я хочу сделать, связана с вводом-выводом, либо в БД, либо в Интернет, я теряюсь во многих вложенных обратных вызовах. Это способ связатьreq а такжеres на любой обратный звонок мне нужно; это супер полезно.
 robkuz08 июл. 2013 г., 21:37
хм, я не уверен, если бы я действительно рекомендовал ваш подход - внешне это кажется правильным - абсолютно так. Однако я думаю, что указанное вами предварительное условие, касающееся исправления обезьян и т. Д., Является недостижимым в реальности, что вызовет проблемы. Помимо этого - очень интересный подход. Может быть, было бы любезно, если бы вы проголосовали за мой вопрос и ответ, если уже ссылались на него ;-)
 Tobia24 июн. 2014 г., 00:36
@owensmartin, пожалуйста. Фактически, я обычно определяю свои обратные вызовы как методы жирной стрелки с описательным именем, чтобы я мог передать их в библиотеки в качестве значений:someLibrary.doSomething 1, 2, @somethingWasDone Это превращает мой код в линейную последовательность вызовов методов, без вложенных пирамид-> и связанные с этим переменные вопросы объема.
 Tobia08 июл. 2013 г., 23:04
Я считаю, что это будет сильно зависеть от типа проекта. В средне-крупномасштабном проекте (от 10 тыс. До мс строк кода) или в проекте, который стремится стать таковым, наличие такой согласованности - хорошая вещь. Зная, что каждый@ в классе whomever всегда означает, что «атрибут текущего экземпляра определяемого класса» неоценим. Неудивительно, что в таких проектах обычно не одобряют исправления обезьян и другие динамические изменения кода по той же причине: это усложняет (замедляет) понимание кода, который вы не писали, поэтому в итоге он стоит дороже. (проголосовал, извините за это)
 Rostyslav Diachok07 окт. 2014 г., 16:29
Даже создатель javascript говорит, что использование наследования прототипов не является хорошей идеей на сегодняшний день.youtube.com/watch?v=bo36MrBfTk4#t=1896

Ваш ответ на вопрос