콜백 함수를 실행할 때 Angular2 구성 요소의 "this"가 정의되지 않았습니다.


94

RESTful 끝점에서 데이터를 가져 오는 서비스를 호출하는 구성 요소가 있습니다. 이 서비스는 해당 데이터를 가져온 후 실행할 콜백 함수를 제공해야합니다.

문제는 콜백 함수를 사용하여 구성 요소 변수의 기존 데이터에 데이터를 추가하려고 할 때 EXCEPTION: TypeError: Cannot read property 'messages' of undefined. this정의되지 않은 이유는 무엇 입니까?

TypeScript 버전 : 버전 1.8.10

컨트롤러 코드 :

import {Component} from '@angular/core'
import {ApiService} from '...'

@Component({
    ...
})
export class MainComponent {

    private messages: Array<any>;

    constructor(private apiService: ApiService){}

    getMessages(){
        this.apiService.getMessages(gotMessages);
    }

    gotMessages(messagesFromApi){
        messagesFromApi.forEach((m) => {
            this.messages.push(m) // EXCEPTION: TypeError: Cannot read property 'messages' of undefined
        })
    }
}

어떤 버전의 TypeScript를 사용하고 있습니까? (당신이 가진 것을 확인하실 수 있습니다 tsc -v)
rinukkusu

forEach 때문에 예외입니다. 대신 For-of를 사용하십시오.
Pax Beach

답변:


158

Function.prototype.bind 함수를 사용하십시오 .

getMessages() {
    this.apiService.getMessages(this.gotMessages.bind(this));
}

여기서 일어나는 일은을 gotMessages콜백으로 전달하는 것입니다. 이것이 실행될 때 범위가 다르므로 this예상 한 것과 다릅니다 .
bind함수는에 바인딩 된 새 함수를 반환합니다.this 정의한에 .

물론 여기 에서 화살표 기능을 사용할 수도 있습니다.

getMessages() {
    this.apiService.getMessages(messages => this.gotMessages(messages));
}

나는 bind구문을 선호 하지만 그것은 당신에게 달려 있습니다.

세 번째 옵션은 다음으로 시작하는 메서드를 바인딩합니다.

export class MainComponent {
    getMessages = () => {
        ...
    }
}

또는

export class MainComponent {
    ...

    constructor(private apiService: ApiService) {
        this.getMessages = this.getMessages.bind(this);
    }

    getMessages(){
        this.apiService.getMessages(gotMessages);
    }
}

1
고마워요! 왜 이런 일이 발생하는지 설명해 주셔서 감사합니다.
Michael Gradek

감사합니다! OOP 스타일이 자바 스크립트 특성 (바인딩)을 유출하고 있다는 사실은 비극적입니다.
skfd

21

아니면 이렇게 할 수 있습니다

gotMessages(messagesFromApi){
    let that = this // somebody uses self 
    messagesFromApi.forEach((m) => {
        that.messages.push(m) // or self.messages.push(m) - if you used self
    })
}

13

함수 참조를 전달하고 있기 때문에 getMessages올바른 this컨텍스트 가 없습니다 .

this익명 함수 내에서 사용하기 위해 올바른 컨텍스트를 자동으로 바인딩하는 람다를 사용하여 쉽게 수정할 수 있습니다 .

getMessages(){
    this.apiService.getMessages((data) => this.gotMessages(data));
}

그거였다! 감사합니다
마이클 Gradek

완전한. 가장 간단하고 효율적인 솔루션.
Kon

1

같은 문제가 있으며 () => {} 대신 function () 사용하여 해결되었습니다.


이것은 기존 답변에 정보를 추가하지 않습니다
DerMike

0

기능을 정의하십시오

gotMessages = (messagesFromApi) => {
  messagesFromApi.forEach((m) => {
    this.messages.push(m)
  })
}

이것은 기존 답변에 정보를 추가하지 않습니다
DerMike
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.