В других ответах важно отметить, что связывание функций жирной стрелкой, когда в этом нет необходимости, может привести к непредвиденным результатам, как, например, в этом примере с классом, который мы просто назовем DummyClass.
class DummyClass
constructor : () ->
some_function : () ->
return "some_function"
other_function : () =>
return "other_function"
dummy = new DummyClass()
dummy.some_function() == "some_function" # true
dummy.other_function() == "other_function" # true
В этом случае функции делают именно то, что можно ожидать, и использование жирной стрелки, похоже, не потеряно, но что происходит, когда мы модифицируем прототип DummyClass после того, как он уже определен (например, изменение какого-либо предупреждения или изменение вывода журнал):
DummyClass::some_function = ->
return "some_new_function"
DummyClass::other_function = ->
return "other_new_function"
dummy.some_function() == "some_new_function" # true
dummy.other_function() == "other_new_function" # false
dummy.other_function() == "other_function" # true
Как мы видим, переопределение нашей ранее определенной функции прототипа приводит к тому, что some_function корректно перезаписывается, но other_function остается неизменной в экземплярах, так как жирная стрелка привела к тому, что other_function из класса привязан ко всем экземплярам, поэтому экземпляры не будут ссылаться обратно в их класс, чтобы найти функцию
DummyClass::other_function = =>
return "new_other_new_function"
dummy.other_function() == "new_other_new_function" # false
second_dummy = new DummyClass()
second_dummy.other_function() == "new_other_new_function" # true
Даже жирная стрелка не будет работать, так как жирная стрелка вызывает привязку функции только к новым экземплярам (которые получают новые функции, как и следовало ожидать).
Однако это приводит к некоторым проблемам: что если нам понадобится функция (например, в случае переключения функции ведения журнала на окно вывода или что-то подобное), которая будет работать во всех существующих экземплярах (включая обработчики событий) [как таковые, мы можем не используйте жирные стрелки в исходном определении], но нам все еще нужен доступ к внутренним атрибутам в обработчике событий [точная причина, по которой мы использовали жирные стрелки, а не тонкие стрелки].
Что ж, самый простой способ сделать это - просто включить две функции в исходное определение класса: одну, определенную тонкой стрелкой, которая выполняет операции, которые вы хотите выполнить, и другую, определенную жирной стрелкой, которая ничего не делает, кроме вызова первая функция например:
class SomeClass
constructor : () ->
@data = 0
_do_something : () ->
return @data
do_something : () =>
@_do_something()
something = new SomeClass()
something.do_something() == 0 # true
event_handler = something.do_something
event_handler() == 0 # true
SomeClass::_do_something = -> return @data + 1
something.do_something() == 1 # true
event_handler() == 1 # true
Так что, когда использовать тонкие / толстые стрелки, можно довольно просто подвести итог четырьмя способами:
При выполнении обоих условий должны использоваться только функции тонкой стрелки:
- Метод никогда не будет передан по ссылке, включая event_handlers, например у вас никогда не бывает таких случаев, как: some_reference = some_instance.some_method; some_reference ()
- И метод должен быть универсальным для всех экземпляров, поэтому, если функция прототипа изменяется, метод изменяется для всех экземпляров
Должны использоваться только функции жирной стрелки, если выполняется следующее условие:
- Метод должен быть точно привязан к экземпляру при создании экземпляра и оставаться постоянно связанным, даже если определение функции изменяется для прототипа, включая все случаи, когда функция должна быть обработчиком события, а поведение обработчика события должно быть согласованным
Функция жирной стрелки, которая напрямую вызывает функцию тонкой стрелки, должна использоваться при соблюдении следующих условий:
- Метод должен вызываться по ссылке, такой как обработчик события
- И функциональность может измениться в будущем, затрагивая существующие экземпляры, заменив функцию тонкой стрелки
Функция тонкой стрелки, которая напрямую вызывает функцию жирной стрелки (не показана), должна использоваться при соблюдении следующих условий:
- Функция жирной стрелки всегда должна быть присоединена к экземпляру
- НО функция тонкой стрелки может измениться (даже на новую функцию, которая не использует оригинальную функцию жирной стрелки)
- И функцию тонкой стрелки не нужно передавать по ссылке
Во всех подходах следует учитывать случай, когда функции прототипа могут быть изменены, будет ли поведение определенных экземпляров вести себя правильно, например, хотя функция определена жирной стрелкой, ее поведение может быть непоследовательным внутри экземпляра. если он вызывает метод, который изменяется в прототипе