클래스 메서드 내부의 타이프 스크립트 "this"


81

나는 이것이 아마도 고통 스러울 정도로 기본적인 것이라는 것을 알고 있지만, 나는 그것을 둘러싼 내 머리를 감싸는 데 어려움을 겪고 있습니다.

class Main
{
     constructor()
     {
         requestAnimationFrame(this.update);  //fine    
     }

     update(): void
     {
         requestAnimationFrame(this.update);  //error, because this is window
     }

}

프록시가 필요한 경우이므로 Jquery를 사용한다고 가정 해 보겠습니다.

class Main
{
     constructor()
     {
         this.updateProxy = $.proxy(this.update, this);
         requestAnimationFrame(this.updateProxy);  //fine    
     }

     updateProxy: () => void
     update(): void
     {
         requestAnimationFrame(this.updateProxy);  //fine
     }

}

그러나 Actionscript 3 배경에서 왔으므로 여기서 무슨 일이 일어나고 있는지 잘 모르겠습니다. 죄송합니다. Javascript가 어디서 시작되고 TypeScript가 끝나는 지 잘 모르겠습니다.

updateProxy: () => void

또한 내가이 일을 제대로하고 있다고 확신하지 못합니다. 내가 원하는 마지막 것은 내가 aProxy()같은 것을 두 번 쓰고 있다고 느낄 때 액세스 해야하는 aa () 함수를 가진 대부분의 클래스입니다 . 정상인가요?


답변:


117

당신이 원하는 경우 this캡처이 일의 타이프의 방법은 화살표 기능을 통해입니다. Anders를 인용하려면 :

this화살표의 기능은 어휘 범위가

이 기능을 활용하는 방법은 다음과 같습니다.

class test{
    // Use arrow functions
    func1=(arg:string)=>{
            return arg+" yeah" + this.prop;
    }
    func2=(arg:number)=>{
            return arg+10 + this.prop;
    }       

    // some property on this
    prop = 10;      
}

TypeScript Playground에서보기

생성 된 JavaScript 에서 함수 호출 외부 에서 this캡처 된 것을 볼 수 있습니다 .

var _this = this;
this.prop = 10;
this.func1 = function (arg) {
    return arg + " yeah" + _this.prop;
};

따라서 this함수 호출 내부 의 값 (일 수 있음 window)은 사용되지 않습니다.

자세히 알아보기 : " thisTypeScript 이해 "(4:05) – YouTube


2
이것은 필요하지 않습니다. 당신이 제안하는 것은 관용적 인 JavaScript이지만 TypeScript는 이것을 불필요하게 만듭니다.
Tatiana Racheva

1
클래스 멤버 컨텍스트에서 화살표 함수를 사용하는 @TatianaRacheva는 TS 0.9.1 이전에 허용되지 않았습니다 (이 답변은 그 이전이었습니다). :) 새로운 구문 업데이트 대답
basarat

18
비디오를 시청해야합니다-매우 유용합니다. 5 분만
Simon_Weaver 2014 년

1
감사합니다, @basarat. 라이트 전구에 대한 상황 동안 계속 최대한 빨리 당신이 당신의 비디오를 화살표 기능 절반 방법을 사용했다한다. 감사합니다.
Simon

1
TypeScript 놀이터에서 @AaronLS를 생성 var _this = this;하려면 선택해야합니다 ES5. ES2015 이후-내부 기능- this대신 사용_this
Stefano Spinucci

18

이와 같이 메소드를 작성하면 'this'가 예상대로 처리됩니다.

class Main
{
    constructor()
    {
        requestAnimationFrame(() => this.update());
    }

    update(): void
    {
        requestAnimationFrame(() => this.update());
    }
}

또 다른 옵션은 'this'를 함수 호출에 바인딩하는 것입니다.

class Main
{
    constructor()
    {
        requestAnimationFrame(this.update.bind(this));
    }

    update(): void
    {
        requestAnimationFrame(this.update.bind(this));
    }
}

2
내 경험상 업데이트 기능은 다음과 같이 더 잘 정의됩니다. update = () => {...}
Shaun Rowan

저는 타이프 스크립트를 많이 사용했고 여러 번 앞뒤로 변경되었습니다. 현재로서는 단순한 메서드 호출 이상인 경우 중괄호 만 포함합니다. 또한 typescript + linq (경건한)를 사용할 때 형식이 더 좋습니다. 예 : Enumerable.From (arr) .Where (o => o.id == 123);
joelnet 2014

생성 된 javascript를 보면 큰 차이가있을 것 같습니다. 맛의 문제가 아닙니다. update = () => {}는 "var _this = this"컴파일을 통해 어휘 범위를 생성하지만 구문은 그렇지 않습니다.
Shaun Rowan 2014

1
"_this"컨텍스트가 절대적으로 포함되어 있으므로 TypeScript 라이브러리를 업그레이드해야 할 수도 있습니다. "() => code ()"또는 () => {return code (); 사용 } "는 100 % 동일한 자바 스크립트 코드를 출력합니다. 출력은 다음과 같습니다. i.imgur.com/I5J12GE.png . 코드를 typescriptlang.org/Playground
joelnet 2014

분명히 바인드 (이) 원래 함수 인수에 유형의 안전을 푼다 때문에 나쁜 일 수있다
로버트 왕

6

타이프 스크립트 언어 사양 https://github.com/Microsoft/TypeScript/blob/master/doc/TypeScript%20Language%20Specification.pdf?raw=true 72 페이지 참조

화살표 함수 표현식

예에서

class Messenger {
 message = "Hello World";
 start() {
 setTimeout(() => alert(this.message), 3000);
 }
};
var messenger = new Messenger();
messenger.start();

화살표 함수 표현식을 사용하면 콜백이 주변의 'start'메소드와 동일한 값을 갖게됩니다. 콜백을 표준 함수 표현식으로 작성하려면 주변에 대한 액세스를 수동으로 정렬해야합니다 (예 : 로컬 변수에 복사).

이것은 실제 생성 된 자바 스크립트입니다.

class Messenger {
 message = "Hello World";
 start() {
 var _this = this;
 setTimeout(function() { alert(_this.message); }, 3000);
 }
};

불행히도 링크가 끊어졌습니다
Jimmy Kane

1
@JimmyKane 링크를 업데이트했습니다. 이상하게도이 문서는 1 년이 넘었고 여전히 홈페이지에서 참조하고 있지만 답변에 포함 된 중요한 내용입니다.
Simon_Weaver

4

함수를 콜백으로 전달할 때 문제가 발생합니다. 콜백이 실행될 때까지 "this"의 값은 Window, 콜백을 호출하는 컨트롤 또는 다른 것으로 변경되었을 수 있습니다.

콜백 할 함수에 대한 참조를 전달할 때 항상 람다 식을 사용해야합니다. 예를 들면

public addFile(file) {
  this.files.push(file);
}
//Not like this
someObject.doSomething(addFile);
//but instead, like this
someObject.doSomething( (file) => addFile(file) );

이것은 다음과 같이 컴파일됩니다.

this.addFile(file) {
  this.files.push(file);
}
var _this = this;
someObject.doSomething(_this.addFile);

addFile 함수는 특정 개체 참조 (_this)에서 호출되기 때문에 호출자의 "this"를 사용하지 않고 대신 _this의 값을 사용합니다.


컴파일 된 내용을 말할 때 어떤 것을 보여주고 있습니까? (화살표 인스턴스 또는 메서드 개체를 전달하는 인스턴스?)
Vaccano

람다. 해당 코드로 TS를 만들고 컴파일되는 내용을 살펴보십시오.
Peter Morris

2

간단히 말해서 this 키워드에는 항상 함수를 호출 한 객체에 대한 참조가 있습니다.

자바 스크립트에서 함수는 변수 일 뿐이므로 전달할 수 있습니다.

예:

var x = {
   localvar: 5, 
   test: function(){
      alert(this.localvar);
   }
};

x.test() // outputs 5

var y;
y.somemethod = x.test; // assign the function test from x to the 'property' somemethod on y
y.test();              // outputs undefined, this now points to y and y has no localvar

y.localvar = "super dooper string";
y.test();              // outputs super dooper string

jQuery로 다음을 수행 할 때 :

$.proxy(this.update, this);

당신이하는 일은 그 맥락을 무시하는 것입니다. 이면에서 jQuery는 다음과 같이 안내합니다.

$.proxy = function(fnc, scope){
  return function(){
     return fnc.apply(scope);  // apply is a method on a function that calls that function with a given this value
  }
};

2

파티에 매우 늦었지만이 질문의 향후 방문자가 다음 사항을 고려하는 것이 매우 중요하다고 생각합니다.

받아 들인 답변을 포함한 다른 답변은 중요한 점을 놓칩니다.

myFunction() { ... }

myFunction = () => { ... }

있다 없다 "후자 캡처 것을 제외하고 같은 일 this".

첫 번째 구문은 프로토 타입에 메서드를 생성하고 두 번째 구문은 값이 함수 인 객체에 속성을 생성합니다. this ). 트랜스 파일 된 JavaScript에서 이것을 명확하게 볼 수 있습니다.

완료하려면 :

myFunction = function() { ... }

두 번째 구문과 동일하지만 캡처하지 않습니다.

따라서 대부분의 경우 화살표 구문 사용하면 객체에 바인딩하는 문제를 해결할 수 있지만 동일하지 않으며 속성 대신 프로토 타입에 적절한 기능을 갖고 싶은 상황이 많이 있습니다.

프록시를 사용하거나 이러한 경우에는 .bind()사실 입니다 올바른 솔루션입니다. (가독성이 좋지는 않지만.)

여기에서 더 많은 것을 읽으십시오 (주로 TypeScript에 관한 것이 아니라 원칙이 있습니다) :

https://medium.com/@charpeni/arrow-functions-in-class-properties-might-not-be-as-great-as-we-think-3b3551c440b1

https://ponyfoo.com/articles/binding-methods-to-class-instance-objects


0

이런 식으로하는 것은 어떻습니까? "myClass"유형의 전역 변수를 선언하고 클래스 생성자에서 초기화합니다.

var _self: myClass;

class myClass {
    classScopeVar: string = "hello";

    constructor() {
        _self = this;
    }

    alerter() {
        setTimeout(function () {
            alert(_self.classScopeVar)
        }, 500);
    }
}

var classInstance = new myClass();
classInstance.alerter();

참고 : "self"를 이미 특별한 의미로 사용하지 않는 것이 중요합니다.

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