programing

TypeScript에 'this' 에 대한 별칭이 있습니까?

megabox 2023. 10. 6. 21:00
반응형

TypeScript에 'this' 에 대한 별칭이 있습니까?

저는 jQuery 이벤트에 대한 이벤트 핸들러 콜백 역할을 하는 메서드를 정의한 클래스를 TypeScript에 작성하려고 했습니다.

class Editor {
    textarea: JQuery;

    constructor(public id: string) {
        this.textarea = $(id);
        this.textarea.focusin(onFocusIn);
    }

    onFocusIn(e: JQueryEventObject) {
        var height = this.textarea.css('height'); // <-- This is not good.
    }
}

onFocusIn 이벤트 핸들러 내에서 TypeScript는 '이것'을 클래스의 '이것'으로 봅니다.그러나 jQuery는 이 참조를 재정의하고 이벤트와 연결된 DOM 개체로 설정합니다.

한 가지 대안은 생성기 내의 람다를 이벤트 핸들러로 정의하는 것입니다. 이 경우 TypeScript는 숨겨진 _this alias를 가진 일종의 클로저를 만듭니다.

class Editor {
    textarea: JQuery;

    constructor(public id: string) {
        this.textarea = $(id);
        this.textarea.focusin((e) => {
            var height = this.textarea.css('height'); // <-- This is good.
        });
    }
}

제 질문은, 이 jQuery 동작을 극복하기 위해 TypeScript를 사용하는 메서드 기반 이벤트 핸들러 내에서 이 참조에 액세스할 수 있는 다른 방법이 있습니까?

의 범위this됩니다를 할 때 됩니다.() => { ... }- 여기 타입스크립트자바스크립트 프로그래머들로부터 가져온 예가 있습니다.

var ScopeExample = { 
  text: "Text from outer function", 
  run: function() { 
    setTimeout( () => { 
      alert(this.text); 
    }, 1000); 
  } 
};

:this.text당신에게 주는Text from outer function화살표 함수 구문은 "소문자 범위"를 유지하기 때문입니다.

그 인 하는 TypeScript 에 했습니다.this포인터 (이것은 단지 jQuery 문제가 아닙니다.)그렇다고 해서 이 문제를 해결할 합리적으로 간단한 방법이 없는 것은 아닙니다.입니다를 에 대한 .this전화를 걸기 전에 포인터를 선택합니다.다.jQuery다라는 .jQuery.proxy()은 그 된 . 입니다(하십시오)).$.proxy()름)

class Editor { 
    textarea: JQuery; 

    constructor(public id: string) { 
        this.textarea = $(id); 
        this.textarea.focusin($.proxy(onFocusIn, this)); 
    } 

    onFocusIn(e: JQueryEventObject) { 
        var height = this.textarea.css('height'); // <-- This is not good. 
    } 
} 

그것은 합리적인 해결책이지만 저는 개인적으로 개발자들이 종종 프록시 호출을 포함하는 것을 잊어버린다는 것을 발견했기 때문에 이 문제에 대한 대체 TypeScript 기반 해결책을 생각해 냈습니다.사용하는 것은.HasCallbacks로 하는 입니다에서 입니다.HasCallbacks해도 상관없습니다.'cb_'그들의 것을 가질 것입니다.this포인터가 영구 바인딩됩니다. 방법은 다로 수 this대부분의 경우 더 좋은 포인터.두 가지 메커니즘 중 하나가 작동하므로 사용하기 쉬운 것은 무엇이든 사용할 수 있습니다.

class HasCallbacks {
    constructor() {
        var _this = this, _constructor = (<any>this).constructor;
        if (!_constructor.__cb__) {
            _constructor.__cb__ = {};
            for (var m in this) {
                var fn = this[m];
                if (typeof fn === 'function' && m.indexOf('cb_') == 0) {
                    _constructor.__cb__[m] = fn;                    
                }
            }
        }
        for (var m in _constructor.__cb__) {
            (function (m, fn) {
                _this[m] = function () {
                    return fn.apply(_this, Array.prototype.slice.call(arguments));                      
                };
            })(m, _constructor.__cb__[m]);
        }
    }
}

class Foo extends HasCallbacks  {
    private label = 'test';

    constructor() {
        super();

    }

    public cb_Bar() {
        alert(this.label);
    }
}

var x = new Foo();
x.cb_Bar.call({});

합니다에 합니다.this항상 엔클로저 클래스를 참조합니다.

그래서 여러분의 질문에 답하기 위해, 여기 두 가지 간단한 해결책이 있습니다.

화살표 구문을 사용하여 메서드 참조

constructor(public id: string) {
    this.textarea = $(id);
    this.textarea.focusin(e => this.onFocusIn(e));
}

화살표 구문을 사용하여 메서드를 정의합니다.

onFocusIn = (e: JQueryEventObject) => {
    var height = this.textarea.css('height');
}

구성원 함수를 생성자의 인스턴스에 바인딩할 수 있습니다.

class Editor {
    textarea: JQuery;

    constructor(public id: string) {
        this.textarea = $(id);
        this.textarea.focusin(onFocusIn);
        this.onFocusIn = this.onFocusIn.bind(this); // <-- Bind to 'this' forever
    }

    onFocusIn(e: JQueryEventObject) {
        var height = this.textarea.css('height');   // <-- This is now fine
    }
}

또는 핸들러를 추가할 때 바인딩하기만 하면 됩니다.

        this.textarea.focusin(onFocusIn.bind(this));

이거 먹어봐요.

class Editor 
{

    textarea: JQuery;
    constructor(public id: string) {
        this.textarea = $(id);
        this.textarea.focusin((e)=> { this.onFocusIn(e); });
    }

    onFocusIn(e: JQueryEventObject) {
        var height = this.textarea.css('height'); // <-- This will work
    }

}

스티븐 아이크먼의 해결책은 편리하지만 불완전합니다.Danny Becket과 Sam의 답변은 더 짧고 더 수동적이며, 역동적이고 어휘적인 범위가 동시에 필요한 콜백을 받는 동일한 일반적인 경우에 실패합니다.아래 설명이 TL;DR인 경우 내 코드로 건너뜁니다.

라이브러리 콜백과 함께 사용하기 위해 동적 범위 지정을 위해 "이것"을 보존해야 하고 클래스 인스턴스에 대한 어휘 범위 지정 기능이 있는 "이것"을 보유해야 합니다.인스턴스를 콜백 생성기로 전달하여 클래스 인스턴스에 대한 매개 변수를 효과적으로 닫게 하는 것이 가장 우수하다고 생각합니다.컴파일러는 당신이 그렇게 하는 것을 놓쳤는지 알려줍니다.저는 어휘 범위 매개 변수를 "outerThis"라고 부르는 관례를 사용하지만, "self" 또는 다른 이름이 더 나을 수 있습니다.

"이" 키워드의 사용은 OOO 세계에서 도용된 것으로, TypeScript가 이 키워드를 채택했을 때(ECMAscript 6 사양에서 추정), 다른 엔티티에 의해 메소드가 호출될 때마다 어휘 범위 개념과 동적 범위 개념을 혼동했습니다.저는 이것에 약간 화가 납니다. 저는 사전 범위 객체 인스턴스를 무시할 수 있도록 TypeScript의 "self" 키워드를 선호합니다.또는 JS는 필요할 때 명시적인 첫 번째 위치 "호출자" 매개변수를 요구하도록 재정의될 수 있습니다(따라서 모든 웹 페이지를 한 번에 깨트릴 수 있습니다).

이것이 제 해결책입니다. (대규모 수업에서 제외)특히 방법을 부르는 방식을 자세히 살펴보고, 특히 "dragmove Lambda"의 본문을 살펴봅니다.

export class OntologyMappingOverview {

initGraph(){
...
// Using D3, have to provide a container of mouse-drag behavior functions
// to a force layout graph
this.nodeDragBehavior = d3.behavior.drag()
        .on("dragstart", this.dragstartLambda(this))
        .on("drag", this.dragmoveLambda(this))
        .on("dragend", this.dragendLambda(this));

...
}

dragmoveLambda(outerThis: OntologyMappingOverview): {(d: any, i: number): void} {
    console.log("redefine this for dragmove");

    return function(d, i){
        console.log("dragmove");
        d.px += d3.event.dx;
        d.py += d3.event.dy;
        d.x += d3.event.dx;
        d.y += d3.event.dy; 

        // Referring to "this" in dynamic scoping context
        d3.select(this).attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });

        outerThis.vis.selectAll("line")
            .filter(function(e, i){ return e.source == d || e.target == d; })
            .attr("x1", function(e) { return e.source.x; })
            .attr("y1", function(e) { return e.source.y; })
            .attr("x2", function(e) { return e.target.x; })
            .attr("y2", function(e) { return e.target.y; });

    }
}

dragging: boolean  =false;
// *Call* these callback Lambda methods rather than passing directly to the callback caller.
 dragstartLambda(outerThis: OntologyMappingOverview): {(d: any, i: number): void} {
        console.log("redefine this for dragstart");

        return function(d, i) {
            console.log("dragstart");
            outerThis.dragging = true;

            outerThis.forceLayout.stop();
        }
    }

dragendLambda(outerThis: OntologyMappingOverview): {(d: any, i: number): void}  {
        console.log("redefine this for dragend");

        return function(d, i) {
            console.log("dragend");
            outerThis.dragging = false;
            d.fixed = true;
        }
    }

}

TypeScript 는 '' 로(의) 로 수 인 방법을 this 이외의 this할 수 백 됨)존 JS백됨)=>표현).

CodePlex 사이트에 제안을 게시할 수 있지만 언어 설계 측면에서는 컴파일러가 제공할 수 있는 모든 정상 키워드가 기존 자바스크립트 코드에서 이미 사용되고 있기 때문에 여기서 일어날 수 있는 은 많지 않을 것입니다.

저도 비슷한 문제에 직면했습니다.사용하시면 될 것 같아요..each()지켜야 할 경우가 많습니다.this나중의 사건에 대한 다른 값으로.

자바스크립트 방식:

$(':input').on('focus', function() {
  $(this).css('background-color', 'green');
}).on('blur', function() {
  $(this).css('background-color', 'transparent');
});

TypeScript 방식:

$(':input').each((i, input) => {
  var $input = $(input);
  $input.on('focus', () => {
    $input.css('background-color', 'green');
  }).on('blur', () => {
    $input.css('background-color', 'transparent');
  });
});

누군가에게 도움이 되었으면 좋겠습니다.

jseval 함수를 사용할 수 있습니다.var realThis = eval('this');

당신은 당신의 참조를 저장할 수 있습니다.this다른 변수에..self아마도, 그리고 그 방법으로 참조에 접근할 수 있습니다.저는 타이프스크립트를 사용하지 않지만, 그것은 과거에 바닐라 자바스크립트로 성공한 방법입니다.

이 블로그 게시물 http://lumpofcode.blogspot.com/2012/10/typescript-dart-google-web-toolkit-and.html, 을 확인해 보세요. TypeScript 클래스 내 및 클래스 간 통화를 구성하는 기술에 대한 자세한 설명이 있습니다.

위의 모든 답변보다 훨씬 간단한 해결책이 있습니다.기본적으로 '이것'을 클래스 '이것'으로 변환하는 '=>' 컨스트럭트 대신 키워드 기능을 사용하여 자바스크립트로 돌아갑니다.

class Editor {
    textarea: JQuery;

    constructor(public id: string) {
        var self = this;                      // <-- This is save the reference
        this.textarea = $(id);
        this.textarea.focusin(function() {   // <-- using  javascript function semantics here
             self.onFocusIn(this);          //  <-- 'this' is as same as in javascript
        });
    }

    onFocusIn(jqueryObject : JQuery) {
        var height = jqueryObject.css('height'); 
    }
}

언급URL : https://stackoverflow.com/questions/12756423/is-there-an-alias-for-this-in-typescript

반응형