2011-11-11 5 views
17

오브젝트 프로토 타입 내에 저장된 이벤트 핸들러에서 this 자바 스크립트 참조를 보존하는 올바른 방법은 무엇입니까? 나는 '_this'또는 'that'과 같은 임시 변수 값을 만들지 말고 jQuery와 같은 프레임 워크를 사용할 수 없습니다. 나는 많은 사람들이 'bind'함수를 사용하는 것에 대해 이야기했지만 주어진 시나리오에서 그것을 구현하는 방법을 알지 못했다.자바 프로토 타입 이벤트 핸들러에서 'this'참조 유지

var Example = function(foo,bar){ 
    this.foo = foo; 
    this.bar = bar; 
}; 
Example.prototype.SetEvent = function(){ 
    this.bar.onclick = this.ClickEvent; 
}; 
Example.prototype.ClickEvent = function(){ 
    console.log(this.foo); // logs undefined because 'this' is really 'this.bar' 
}; 

답변

20

나는 bind() 지금까지 가장 깨끗한 솔루션 인 찾기 :

this.bar.onclick = this.ClickEvent.bind(this); 

이 BTW 다른 this 매우 자주 관례 that라고합니다. bind에 MDN 문서 밖으로

+3

"*"(this는 "Crockford")에 대한 참조를 만듭니다. 나는 "인스턴스"(라 스테파노 프), 또는 "나"(ExtJS)를 선호합니다. –

+4

사실, 어떻게 이름을 붙이더라도'this' 참조를 만드는 것이 싫어요. 그러나 동의하면, '그'가 최고의 이름이 아니다. –

+1

필자는 'self'를 사용하지만 최근에는 WebWorkers의 최상위 속성과 이름 충돌이 있음을 발견했습니다. 당신은 같은 이름을 가질 수는 없지만, 그것은 혼란 스럽습니다. 또한, 나는 'this'와 상당히 반대되는 이름을 발견했습니다. – Matt

7

확인 : https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind

이 기능을 사용하면 (무엇 this) 범위를 변경할 수 있습니다

Example.prototype.SetEvent = function(){ 
    this.bar.onclick = this.ClickEvent.bind(this); 
}; 

이 새로 추가되었습니다, 그러나,주의 따라서 모든 사용자 에이전트에서 지원되지 않을 수 있습니다. 위에 링크 된 MDN 문서에는 폴리 필이 있습니다.

3

bind의 문제점은 only supported by IE9+입니다.

이 기능은 es5-shim와 polyfilled 있지만 기본 구현 완전히 동일하지입니다 수 있습니다

  • 주의 할을 : 바운드 함수는 프로토 타입 속성이 있습니다.
  • 주의 : 바운드 함수는 argumentscaller 속성을 처리하지 못하도록 너무 열심히 시도하지 않습니다.
  • 경고 : 바인딩 된 함수는 생성자로 실행되지 않도록 callapply에 체크하지 않습니다.

또 다른 대안은 jQuery.proxy 될 수 있습니다

$(elem).on('click', $.proxy(eventHandler, this)); 

이 훨씬 더 도움이 될 것입니다 당신이 기능은 proxy 방법, jQuery를 통과 할 때 때문에, 나중에 이벤트 핸들러를 제거하려면 새로운 guid 값을 생성 한 다음 원래의 함수 참조를 사용하여 프록시 된 이벤트 처리기 콜백을 바인딩 해제 할 수 있도록 해당 guid를 핵심 함수와 결과 프록시 함수에 모두 적용합니다.

$(elem).off('click', eventHandler); 
+0

'.bind)'는'$ .proxy'보다 완전히 크로스 브라우저가 아닙니다. 이것은 기본적으로'.bind()'의 비표준 버전입니다. 나열된 경고가 실제로 우려된다면,'$ .proxy'는 더 나아지지 않을 것입니다. jQuery를 사용할 수 없다는 것은 분명합니다. –

+0

@squint'$ .proxy' (또는 유사한 구현체)는 연결이 느슨하기 때문에 사용하는 것이 좋습니다. 이것은 OO 이벤트 처리에 실제로 도움이되는 항목입니다. 하지만 폴리 필링 된'.bind()'는'$ .proxy'보다 완전히 크로스 브라우저가 아니기 때문에 제 답변을 업데이트 해 드리겠습니다. –

0

기타 해결책 : ES6에서 소개 한 "화살표 기능"을 사용하십시오. 그것들은 문맥을 바꾸지 않는 특이성을 가지고 있는데, 무엇을 this가 가리킨다.

그것으로주의 하시고

function Foo(){ 
    myeventemitter.addEventListener("mousedown", (()=>{ 
     return (event)=>{this.myinstancefunction(event)}; /* Return the arrow 
function (with the same this) that pass the event to the Foo prototype handler */ 
    })()); 
} 
Foo.prototype.myinstancefunction = function(event){ 
    // Handle event in the context of your Object 
} 

Arrow function specs @ MDN

편집 예를 들면 다음과 같습니다. 클라이언트 측에서 JS 인터프리터의 기능을 확신 할 수 없다면 이전 브라우저에서는 화살표 기능 (see CanIUse stats)을 인식하지 못합니다. 이 메소드는 실행 방법을 알고있는 경우에만 사용하십시오 (최신 브라우저 전용 & NodeJS 응용 프로그램)