2012-07-09 4 views
7

나는 여전히 js oop에서 나를 괴롭히는 문제가있다 - 나는 그것을 나쁘게하고있다라고 확신한다. 그러나 나는 그것을 올바르게하는 방법을 알지 못한다. 그 내가 참조를 잃은 탓에 "이"-자바 스크립트 OOP - 비동기 콜백에서 이것을 잃어버린

예를 들어,이 코드

Auth.prototype.auth = function() { 
    var request = new XMLHttpRequest(); 

    request.open('GET', this.getAuthServerURL() + '/token', true); 
    request.send(); 

    request.onloadend = function() { 
     var response = JSON.parse(request.responseText); 

     console.log(response); 
     if(response.result == 'found') { 
     var token = response.token; 

     this.setToken(token); 
     this.isSigned = true; 
     } else { 
     console.log('Not logged yet.'); 
     } 
    } 
} 

이 문제는 내가 "request.onloadend"기능의 맥락에서 setToken을 기능에 대한 액세스를 질수 있다는 것입니다.

이 문제의 해결책은 무엇입니까? 어떻게 든이 "var"변수를이 함수의 컨텍스트에 전달할 수 있습니까?

감사합니다.

var self = this; 
request.onloadend = function() { 
    ... 
    self.setToken(token); 
    ... 
}; 

답변

4

은 몇 가지가 있습니다

당신은 단지 외부 범위에 대한 참조를 캡처 할 수 있습니다
+0

나는 다른 것이 더 직접적이라고 생각한다. 코드는 최소한으로 바뀌므로 어떤 의사 키워드를 사용할 지 결정할 필요가 없다. 그냥 말해. – Esailija

+0

@Esailija : 저도 그렇지만 슬프게도 그 실질적인 가치는 브라우저 호환성으로 인해 제한됩니다. – Jon

+0

'XHR.onloaded'와의 근원 점 – Esailija

1

, 나는 식별자 self을 사용했습니다, 그러나 더 의미 론적 의미를 이름을 주시기 바랍니다 이것을하는 방법.

Auth.prototype.auth = function() { 
    var request = new XMLHttpRequest(); 
    var self = this; // save "this" value 

    request.open('GET', this.getAuthServerURL() + '/token', true); 
    request.send(); 

    request.onloadend = function() { 
     var response = JSON.parse(request.responseText); 

     console.log(response); 
     if(response.result == 'found') { 
     var token = response.token; 

     self.setToken(token); // use saved "this" value 
     self.isSigned = true; 
     } else { 
     console.log('Not logged yet.'); 
     } 
    } 
} 

또 다른 방법은 bind 사용하는 것입니다 : 가장 직접적인은 단순히 당신이 필요로하는 값의 복사본을 저장하는 것입니다

request.onloadend = (function() { 
    var response = JSON.parse(request.responseText); 

    console.log(response); 
    if(response.result == 'found') { 
    var token = response.token; 

    this.setToken(token); // use saved "this" value 
    this.isSigned = true; 
    } else { 
    console.log('Not logged yet.'); 
    } 
}).bind(this); 

두 번째 방법은 "청소기"하지만, 브라우저 호환성 문제가 있습니다 (IE < 9는 지원하지 않습니다.) 콜백 전에

1

캡처 this :

Auth.prototype.auth = function() { 
    var self = this; 

    var request = new XMLHttpRequest(); 

    request.open('GET', this.getAuthServerURL() + '/token', true); 
    request.send(); 

    request.onloadend = function() { 
     var response = JSON.parse(request.responseText); 

     console.log(response); 
     if(response.result == 'found') { 
     var token = response.token; 

     self.setToken(token); 
     self.isSigned = true; 
     } else { 
     console.log('Not logged yet.'); 
     } 
    } 
} 
2

.bind 기능 : 콜백 외부 지역 VAR에

Auth.prototype.auth = function() { 
    var request = new XMLHttpRequest(); 

    request.open('GET', this.getAuthServerURL() + '/token', true); 
    request.send(); 

    request.onloadend = function() { 
     var response = JSON.parse(request.responseText); 

     console.log(response); 
     if(response.result == 'found') { 
     var token = response.token; 

     this.setToken(token); 
     this.isSigned = true; 
     } else { 
     console.log('Not logged yet.'); 
     } 
    }.bind(this); //<-- bound 
} 
0

저장 this.

Auth.prototype.auth = function() { 
    var request = new XMLHttpRequest(); 
    var _this = this; 

    request.open('GET', this.getAuthServerURL() + '/token', true); 
    request.send(); 

    request.onloadend = function() { 
     var response = JSON.parse(request.responseText); 

     console.log(response); 
     if(response.result == 'found') { 
     var token = response.token; 

     _this.setToken(token); 
     _this.isSigned = true; 
     } else { 
     console.log('Not logged yet.'); 
     } 
    } 
} 
0

당신은 확실히 맞다 : 콜백은 문맥으로 XMLHTTPRequest 객체 (this의 즉, 값)를 호출합니다.

Auth.prototype.auth = function() { 
    var request = new XMLHttpRequest(), 
     authInstance = this; 

    request.open('GET', this.getAuthServerURL() + '/token', true); 
    request.send(); 

    request.onloadend = function() { 
     var response = JSON.parse(request.responseText); 

     console.log(response); 
     if(response.result == 'found') { 
     var token = response.token; 

     authInstance.setToken(token); 
     authInstance.isSigned = true; 
     } else { 
     console.log('Not logged yet.'); 
     } 
    } 
} 

See this answer to another question for more explanation of why this is necessary을 : 당신이 콜백의 범위 내에서 액세스 할 수 있도록, 인스턴스 다른 이름을 부여해야합니다. self 대신 authInstance을 사용했습니다. 왜냐하면 일반적으로 설명적인 변수 이름을 사용하는 것이 좋습니다. 당신은 authInstance이 의미하는 바를 결코 고쳐야하지 않을 것입니다. 반면에 self은 미래에 누군가가 (아마도 여러분!) 코드를 읽을 때 모호 할 수 있습니다.

또 다른 옵션은 bind을 사용하는 것입니다.하지만 여기서는 필요한 것보다 더 복잡 할 수 있습니다.

+0

대부분의 코드를 수정하고 별도의 "키워드"와 추가 변수를 사용하는 것은 간단히 ".bind (this)"를 종료? – Esailija

+0

@Esailija 나는 'bind'형태가 덜 직관적이고 읽기 쉽다고 생각한다. 문맥은 함수의 끝 부분에서만 명확 해지고 함수는 꽤 길다. 그것이 두 줄의 기능이라면, 나는 당신과 동의 할 것입니다. – lonesomeday

+0

클래스의 현재 인스턴스 ([바인딩이 구현되는 방법에 관계없이] (http://en.wikipedia.org/wiki/Dynamic_dispatch))의 현재 인스턴스를 참조하는 클래스 'this'는 내 의견으로는 더 직관적입니다. 그러나 우리는 그것에 동의 할 수 없습니다. – Esailija

관련 문제