CoffeeScript, kiedy użyć strzałki fat ( = > ) nad strzałką ( - > ) i odwrotnie

Podczas budowania klasy w CoffeeScript, czy wszystkie metody instancji powinny być zdefiniowane za pomocą operatora => ("strzałka fat"), a wszystkie statyczne metody powinny być zdefiniowane za pomocą operatora ->?

Author: royhowie, 2012-01-23

4 answers

Nie, Nie tego bym użył.

Głównym przypadkiem użycia, jaki znalazłem dla strzałki fat w definiowaniu metod, jest to, gdy chcesz użyć metody jako wywołania zwrotnego i ta metoda odwołuje się do pól instancji:

class A
  constructor: (@msg) ->
  thin: -> alert @msg
  fat:  => alert @msg

x = new A("yo")
x.thin() #alerts "yo"
x.fat()  #alerts "yo"

fn = (callback) -> callback()

fn(x.thin) #alerts "undefined"
fn(x.fat)  #alerts "yo"
fn(-> x.thin()) #alerts "yo"

Jak widzisz, możesz napotkać problemy z przekazaniem odwołania do metody instancji jako wywołania zwrotnego, jeśli nie użyjesz strzałki fat. Dzieje się tak dlatego, że fat-arrow wiąże instancję obiektu this, podczas gdy thin-arrow Nie, więc metody thin-arrow nazywane są wywołania zwrotne jak powyżej nie mogą uzyskać dostępu do pól instancji, takich jak @msg lub wywołać inne metody instancji. Ostatnia linia jest obejściem dla przypadków, w których zastosowano cienką strzałkę.

 149
Author: nicolaskruchten,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-21 19:59:47

Punkt nie wymieniony w innych odpowiedziach, który należy pamiętać, że powiązanie funkcji ze strzałką fat, gdy nie jest to konieczne, może prowadzić do niezamierzonych wyników, takich jak w tym przykładzie z klasą, którą po prostu wywołamy 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

W tym przypadku funkcje robią dokładnie to, czego można się spodziewać i wydaje się, że nie ma strat w użyciu strzałki fat, ale co się stanie, gdy zmodyfikujemy prototyp DummyClass po jego zdefiniowaniu (np. zmieniając jakiś alert lub zmieniając wyjście logu):

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

Jak widzimy nadpisanie naszej wcześniej zdefiniowanej funkcji prototypu powoduje poprawne nadpisanie some_function, ale inna_function pozostaje taka sama na instancjach, ponieważ strzałka fat spowodowała, że inna_function z klasy jest powiązana ze wszystkimi instancjami, więc instancje nie będą odwoływać się do swojej klasy, aby znaleźć funkcję

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

Nawet fat arrow nie będzie działać, ponieważ fat arrow powoduje tylko powiązanie funkcji z nowymi instancjami (które zyskują nowe funkcje jak można się było spodziewać).

Prowadzi to jednak do pewnych problemów, co jeśli potrzebujemy funkcji (np. w przypadku przełączania funkcji logowania do skrzynki wyjściowej lub czegoś takiego), która będzie działać na wszystkich istniejących instancjach (włączając w to programy obsługi zdarzeń) [jako takie nie możemy używać strzałek fat w oryginalnej definicji], ale nadal potrzebujemy dostępu do wewnętrznych atrybutów w programie obsługi zdarzeń[dokładnie dlatego użyliśmy strzałek fat, a nie cienkich strzałek].

Cóż, najprostszym sposobem, aby to osiągnąć, jest tylko włączenie dwie funkcje w oryginalnej definicji klasy, jedna zdefiniowana za pomocą cienkiej strzałki, która wykonuje operacje, które chcesz wykonać, a druga zdefiniowana za pomocą strzałki fat, która nie robi nic poza wywołaniem pierwszej funkcji, na przykład:

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

Więc kiedy używać cienkich / grubych strzałek można podsumować dość łatwo na cztery sposoby:

  1. Same funkcje cienkiej strzałki powinny być używane, gdy oba warunki są spełnione:

    • metoda nigdy nie zostanie przekazana przez odniesienie, w tym event_handlers np. nigdy nie masz sprawy takiej jak: some_reference = some_instance.some_method; some_reference()
    • i metoda powinna być uniwersalna dla wszystkich instancji, więc jeśli funkcja prototypu ulegnie zmianie, to metoda powinna być uniwersalna dla wszystkich instancji
  2. Same funkcje Strzałki Fat powinny być używane, gdy spełniony jest następujący warunek:

    • metoda powinna być ściśle powiązana z instancją podczas tworzenia instancji i pozostać trwale powiązana, nawet jeśli zmiany definicji funkcji dla prototypu, obejmują wszystkie przypadki, w których funkcja powinna być funkcją obsługi zdarzeń, a zachowanie obsługi zdarzeń powinno być spójne
  3. Funkcja Strzałki Fat, która bezpośrednio wywołuje funkcję cienkiej strzałki, powinna być używana, gdy spełnione są następujące warunki:

    • metoda musi być wywołana przez odniesienie, takie jak obsługa zdarzenia
    • i funkcjonalność może ulec zmianie w przyszłości wpływając na istniejące instancje przez zastępowanie funkcji cienkiej strzałki
  4. Funkcja cienkiej strzałki, która bezpośrednio wywołuje (nie wykazano) funkcję strzałki fat, powinna być używana, gdy spełnione są następujące warunki:

    • funkcja strzałki fat musi być zawsze dołączona do instancji
    • Funkcja cienkiej strzałki może się jednak zmienić (nawet na nową funkcję, która nie korzysta z oryginalnej funkcji strzałki fat)]}
    • i funkcja cienkiej strzałki nigdy nie musi być przekazywana odniesienie

We wszystkich podejściach należy wziąć pod uwagę w przypadku, gdy funkcje prototypowe mogą zostać zmienione, czy zachowanie dla określonych instancji będzie zachowywać się poprawnie, na przykład chociaż funkcja jest zdefiniowana za pomocą strzałki fat, jej zachowanie może nie być spójne w instancji, jeśli wywoła metodę zmienioną w prototypie

 12
Author: Jamesernator,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-04 03:07:51

Zazwyczaj, -> jest w porządku.

class Foo
  @static:  -> this
  instance: -> this

alert Foo.static() == Foo # true

obj = new Foo()
alert obj.instance() == obj # true

Zwróć uwagę, jak metoda statyczna zwraca obiekt klasy dla this, A instancja zwraca obiekt instancji dla this.

Dzieje się tak, że składnia wywołania dostarcza wartości this. W tym kodzie:

foo.bar()

foo domyślnie będzie kontekstem funkcji bar(). Więc to działa tak, jak chcesz. Strzałkę fat potrzebujesz tylko, gdy wywołujesz te funkcje w inny sposób, który nie używa kropki składnia wywołania.

# Pass in a function reference to be called later
# Then later, its called without the dot syntax, causing `this` to be lost
setTimeout foo.bar, 1000

# Breaking off a function reference will lose it's `this` too.
fn = foo.bar
fn()

W obu tych przypadkach użycie strzałki fat do zadeklarowania, że funkcja pozwoliłaby im działać. Ale jeśli nie robisz czegoś dziwnego, zazwyczaj nie musisz.

Więc używaj -> dopóki naprawdę nie potrzebujesz => i nigdy nie używaj => domyślnie.

 9
Author: Alex Wayne,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-03 20:36:38

Just an example for unstanding the fat arrow

Nie działa: (@canvas undefined)
class Test
  constructor: ->
    @canvas = document.createElement 'canvas'
    window.addEventListener 'resize', ->
      @canvas.width = window.innerWidth
      @canvas.height = window.innerHeight

Działa: (@canvas defined)

class Test
  constructor: ->
    @canvas = document.createElement 'canvas'
    window.addEventListener 'resize', =>
      @canvas.width = window.innerWidth
      @canvas.height = window.innerHeight
 5
Author: user3896501,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-18 20:37:07