CoffeeScript, 화살표 (->) 위에 지방 화살표 (=>)를 사용하는 경우와 그 반대


답변:


157

아니요, 이것이 제가 사용하는 규칙이 아닙니다.

메소드 정의에서 핵심 화살표에 대해 찾은 주요 유스 케이스는 메소드를 콜백으로 사용하고 해당 메소드가 인스턴스 필드를 참조하는 경우입니다.

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"

보시다시피, 화살표를 사용하지 않으면 인스턴스의 메소드에 대한 참조를 콜백으로 전달하는 데 문제가 발생할 수 있습니다. 지방 화살표는 객체의 인스턴스를 바인딩 this하지만 얇은 화살표는 그렇지 않기 때문에 위와 같이 콜백이라고 불리는 얇은 화살표 메소드는 @msg다른 인스턴스 메소드 와 같이 인스턴스의 필드에 액세스 하거나 호출 할 수 없습니다 . 마지막 행은가는 화살표가 사용 된 경우에 대한 해결 방법입니다.


2
당신이 사용할 때해야합니까 this얇은 화살표에서 호출 될 것을, 또한 인스턴스 변수는 지방 화살표로 얻을 것이라고?
Andrew Mao

내가 말했듯이 "마지막 줄은가는 화살표가 사용 된 경우에 대한 해결 방법이 있습니다."
nicolaskruchten

내 질문을 오해 한 것 같아 콜백의 기본 범위 this가 사용하려는 변수로 설정 되었다고 가정하십시오 . 그러나 클래스 메서드 this를 참조 하고 싶기 때문에 클래스도 참조하고 싶습니다 . 에 대해 하나의 할당 만 선택할 this수 있으므로 두 변수를 모두 사용할 수있는 가장 좋은 방법은 무엇입니까?
Andrew Mao

@AndrewMao 당신은 아마 내가 의견에 답변을하지 않고이 사이트에 전체 질문을 게시해야합니다 :)
nicolaskruchten

괜찮습니다. 질문은 그렇게 중요하지 않습니다. 그러나 마지막 코드 줄에서 언급 한 것이 아니라는 것을 분명히하고 싶었습니다.
Andrew Mao

13

주목해야 할 다른 답변에서 언급되지 않은 요점은 필요하지 않을 때 팻 화살표로 함수를 바인딩하면이 예제에서 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을 올바르게 덮어 쓰지만, fat 화살표로 인해 클래스의 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

따라서 얇고 뚱뚱한 화살표를 사용할 때 다음 네 가지 방법으로 상당히 쉽게 요약 할 수 있습니다.

  1. 두 조건이 모두 충족 될 때 얇은 화살표 만 사용되어야합니다.

    • 메소드는 event_handlers를 포함하여 참조로 전달되지 않습니다. 예를 들어 다음과 같은 경우는 없습니다. some_reference = some_instance.some_method; some_reference ()
    • 그리고 프로토 타입 함수가 변경되면 모든 인스턴스에서 메소드가 변경되므로 모든 인스턴스에서 메소드가 보편적이어야합니다.
  2. 다음 조건이 충족 될 때 팻 화살표 만 기능을 사용해야합니다.

    • 이 메소드는 인스턴스 작성시 인스턴스에 정확하게 바인딩되어야하고 함수 정의가 프로토 타입에 대해 변경 되더라도 영구적으로 바인딩 된 상태를 유지해야합니다. 여기에는 함수가 이벤트 핸들러 여야하고 이벤트 핸들러 동작이 일관되어야하는 모든 경우가 포함됩니다.
  3. 다음 조건이 충족되면 얇은 화살표 기능을 직접 호출하는 팻 화살표 기능을 사용해야합니다.

    • 이벤트 핸들러와 같은 참조로 메소드를 호출해야합니다.
    • 얇은 화살표 기능을 대체하여 기존 인스턴스에 영향을주는 기능이 향후 변경 될 수 있습니다.
  4. 다음 조건이 충족 될 때 팻 화살표 (미도시) 기능을 직접 호출하는 얇은 화살표 기능을 사용해야합니다.

    • 팻 화살표 기능은 항상 인스턴스에 연결되어야합니다
    • 그러나가는 화살표 기능이 변경 될 수 있습니다 (원래의 지방 화살표 기능을 사용하지 않는 새로운 기능으로도)
    • 얇은 화살표 기능은 참조로 전달할 필요가 없습니다.

모든 접근법에서 특정 인스턴스에 대한 동작이 올바르게 작동하는지 여부와 같이 프로토 타입 함수가 변경 될 수있는 경우에 고려해야합니다. 예를 들어 함수가 굵은 화살표로 정의되어 있지만 호출하면 해당 동작이 인스턴스 내에서 일관성이 없을 수 있습니다 프로토 타입 내에서 변경된 방법


9

보통 ->은 괜찮습니다.

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

alert Foo.static() == Foo # true

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

정적 메소드가에 대한 클래스 객체를 this반환하고 인스턴스가에 대한 인스턴스 객체를 반환하는 방법에 유의하십시오 this.

일어나고있는 것은 호출 구문이의 값을 제공하고 있다는 것입니다 this. 이 코드에서 :

foo.bar()

foobar()기본적으로 함수 의 컨텍스트가 됩니다. 그래서 그것은 단지 당신이 원하는 방식으로 작동합니다. 도트 구문을 호출에 사용하지 않는 다른 방식으로 이러한 함수를 호출 할 때는 팻 화살표 만 필요합니다.

# 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()

두 경우 모두 뚱뚱한 화살표를 사용하여 해당 기능을 선언하면 작동 할 수 있습니다. 그러나 이상한 일을하지 않는 한 보통 필요하지 않습니다.

따라서 ->실제로 필요할 때까지 =>사용 =>하고 기본적으로 사용하지 마십시오 .


1
다음과 같은 경우 실패합니다 :x = obj.instance; alert x() == obj # false!
nicolaskruchten

2
물론 그렇습니다. 그러나 "잘못하고 있습니다". 나는 내 대답을 편집 =>하고 클래스의 정적 / 인스턴스 메소드에 필요할 때를 설명했다 .
Alex Wayne

Nitpick : // is not a CoffeeScript comment반면 # is a CoffeeScript comment.
nicolaskruchten

어떻게 setTimeout foo.bar, 1000"잘못 그 일을?" 지방 화살표를 사용하는 것이 setTimeout (-> foo.bar()), 1000IMHO를 사용하는 것보다 훨씬 좋습니다 .
nicolaskruchten

1
@nicolaskruchten setTimeout물론, 그 구문에 대한 경우 가 있습니다. 그러나 첫 번째 의견은 다소 고안된 것이며 합법적 인 사용 사례는 나타내지 않지만 어떻게 중단 될 수 있는지를 보여줍니다. 나는 단순히 =>인스턴스화에 바인딩 해야하는 새로운 함수를 생성하는 성능 비용이있는 클래스 인스턴스 메소드에서 특별한 이유로 필요하지 않으면 사용 하지 말아야한다고 말하고 있습니다.
Alex Wayne

5

뚱뚱한 화살표를 이해하지 못하는 예

작동하지 않습니다 : (@canvas undefined)

class Test
  constructor: ->
    @canvas = document.createElement 'canvas'
    window.addEventListener 'resize', ->
      @canvas.width = window.innerWidth
      @canvas.height = window.innerHeight

작동 : (@canvas 정의)

class Test
  constructor: ->
    @canvas = document.createElement 'canvas'
    window.addEventListener 'resize', =>
      @canvas.width = window.innerWidth
      @canvas.height = window.innerHeight
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.