2013-03-09 2 views
0

하위 클래스로 재정의 할 수 있지만 콜백으로 사용할 수있는 메소드로 클래스를 만들고 싶습니다. 하나 또는 다른 상황에서만 원하는 동작을 얻을 수있는 것 같습니다. 다음은 예입니다 :어떻게 메소드를 오버라이드하고 coffeescript에서 콜백으로 사용할 수 있습니까?

class Parent 
    constructor:() -> 
     @foo = "foo" 

    fooNotAlwaysDefined:() -> 
     console.log("In parent.fooNotAlwaysDefined, @foo:#{@foo}") 

    childNotCalled:() => 
     console.log("In parent.childNotCalled, @foo:#{@foo}") 

class Child extends Parent 
    fooNotAlwaysDefined:() -> 
     console.log("In child.fooNotAlwaysDefined, @foo:#{@foo}") 

    childNotCalled:() -> 
     console.log("In child.childNotCalled, @foo:#{@foo}") 

c = new Child() 
c.fooNotAlwaysDefined() 
c.childNotCalled() 
process.nextTick(c.fooNotAlwaysDefined) 
process.nextTick(c.childNotCalled) 

자식 함수를 호출하고 @foo 모두 사용의 범위에 있어야 할 내가 원하는 것은 (C 콜백 등.). 여기에 출력 내가 얻을 것 :

child.fooNotAlwaysDefined, @foo에서 : foo는

parent.childNotCalled에서, @foo : foo는

child.fooNotAlwaysDefined에서, @foo : 정의되지 않은

parent.childNotCalled, @foo에서

: 푸

내가 찾은 가장 좋은 해결 방법은 내가 익명 FUNC 내부 fooNotAlwaysDefined을 포장 할 수 있다는 것입니다 process.nextTick에 주어진 것이지만 그 이상은 아닙니다. child.fooNotAlwaysDefined, @foo에서

process.nextTick(() -> c.fooNotAlwaysDefined()) 

: foo는

은 내가 원하는 동작을 얻을 수 있도록 수업을 구성하는 방법이 있나요?

EDIT : Answer : 아래의 매우 유용한 설명을 요약하면 childNotCalled와 관련된 동작이 버그라는 것입니다. 이 동작이 1.6.1에서 발생한다는 것을 알 수 있으므로 개선되었을 수도 있지만이 문제는 해결되지 않습니다.

두 번째 편집 : 문제는 완전히 1.6.2에서 해결 된 것 같습니다.

답변

2

이것은 올바르게 바운드되지 않는 this의 고전적인 문제입니다. 이미 발견 한 해결책 외에도 두 가지 해결책이 있습니다.

뚱뚱한 화살을 사용하여 childNotCalled을 정의 할 수 있습니다.

Meh, 다소 심한. Fat arrowed 메서드는 "일반적으로 작동하지만"게으르며 this의 값을 생각하지 않도록 코드 냄새의 일종입니다. 클리너 방법 :

process.nextTick child.fooNotAlwaysDefined.bind(child) 

이 그것을 익명 함수를 포장 대략 해당하지만, 더 선언적 하고 당신이 뭔가에 child 변수를 재 할당 할 경우에도 작동합니다. thischild에 바인딩 된 fooNotAlwaysDefined의 새 인스턴스를 반환하므로 다음 틱에서 실행될 때 올바른 this이됩니다.

이것은 굵은 화살표가있는 메소드를 선언하는 것과 매우 유사합니다. 코드의 행에서 옳은 일을하고 있음을 알 수 있기 때문에 더 명료하고 효율적이며 이해하기 쉽습니다. 정확성을 보장하기 위해 방법의 정의를 확인하는 대신).

굵은 화살표를 사용하지 않는 한 수퍼 클래스의 굵은 화살표가 자식 메서드의 구현을 오버라이드한다는 사실은 나에게 매력적이지 않게 만드는 또 다른 요소입니다 (컴파일 된 코드를 확인하여 이것이 왜 있는지 알아보십시오. 그것을 할 수 있고 주위에 방법이 없습니다 (굵은 화살표 방법을 금지하는 것을 제외하고), 그러나 그것은 당신이 기대하는 것이 아닙니다.) 이것이 CoffeeScript의 특징입니다. 우리가 없이는 더 좋을 것이라고 생각합니다.

+1

을, 자식 방법으로 지방 화살표를 사용하는 것입니다 *하지 * 작동합니다. 부모 생성자는 자식 생성자 다음에 * 호출됩니다. 즉, 부모 메서드는 궁극적으로 바인딩되어 개체에 저장됩니다. – cspotcode

+0

@cspotcode 와우, 네가 맞아. 나는 커피 스크립트가 합리적인 일을한다고 생각했습니다. 내 엉덩이. 이 동작을 CoffeeScript 컴파일러의 버그로 간주하지 않는 이유가 있습니까? 말하자면,이 행동이 바람직한 시나리오가 있습니까? –

+0

@cspotcode이 버그는 1.6.0에서 소개되었지만 1.6.1에서 수정 된 것이 아닌 것으로 보이며 다음 릴리스에서 제대로 수정 될 것입니다. 휴. https://github.com/jashkenas/coffee-script/issues/2781 –

0

이것은 Underscore의 bindAll 메서드가 설계된 것과 같습니다. 콜백으로 사용할 수 있도록 메소드 세트를 this에 바인드합니다. 또한 CoffeeScript의 굵은 화살표 구문을 사용하여 실패한 것으로 보이는 상속을 사용하면 효과적입니다. 밑줄의 bindAll 방법은 청소기 사용

for methodName in ['fooNotAlwaysDefined', 'childNotCalled'] 
    @[methodName] = do(method = @[methodName]) => 
     => method.apply @, arguments 

: 당신은 밑줄 또는 LoDash를 사용하지 않을 경우

http://underscorejs.org/#bindAll

, 당신은 Parent의 생성자에 다음을 추가하여 직접 수행 할 수 있습니다

_.bindAll @, 'fooNotAlwaysDefined', 'childNotCalled' 

오래된 브라우저와의 호환성에 대해 걱정하지 않는다면 (r 노드에서 unning)는, 당신은 기능이 내장 된 것을 bind 방법 가정 할 수있다 : 사실

@fooNotAlwaysDefined = @fooNotAlwaysDefined.bind @ 
@childNotCalled = @childNotCalled.bind @ 
관련 문제