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는 'this'를 클래스의 'this'로 간주합니다. 그러나 jQuery는이 참조를 재정의하고 이벤트와 관련된 DOM 개체로 설정합니다.
한 가지 대안은 생성자 내에서 람다를 이벤트 핸들러로 정의하는 것입니다.이 경우 TypeScript는 숨겨진 _this 별칭을 사용하여 일종의 클로저를 만듭니다.
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 참조에 액세스하는 다른 방법이 있습니까?
따라서 언급했듯이 메서드가 항상 this
포인터에 바인딩되도록하는 TypeScript 메커니즘이 없습니다 (이는 단순한 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
화살표 함수 구문을 사용할 때 유지됩니다. () => { ... }
여기 JavaScript 프로그래머 용 TypeScript 에서 가져온 예제가 있습니다 .
var ScopeExample = {
text: "Text from outer function",
run: function() {
setTimeout( () => {
alert(this.text);
}, 1000);
}
};
참고 this.text
를 제공 Text from outer function
화살표 함수 구문은 "어휘 범위"를 유지하기 때문이다.
다른 답변 중 일부에서 다루었 듯이 화살표 구문을 사용하여 함수를 정의하면 참조 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
}
}
Steven Ickman의 솔루션은 편리하지만 불완전합니다. Danny Becket과 Sam의 답변은 더 짧고 수동적이며 동시에 동적 및 어휘 범위 "this"가 모두 필요한 콜백이있는 동일한 일반적인 경우에서 실패합니다. 아래 설명이 TL; DR이면 내 코드로 건너 뛰십시오 ...
나는 도서관 콜백에 사용 "이"동적에 대한 범위 지정을 유지해야 하고 내가 클래스 인스턴스에 "이"와 어휘 범위 지정이 필요합니다. 인스턴스를 콜백 생성기로 전달하여 클래스 인스턴스에 대한 매개 변수 클로저를 효과적으로 허용하는 것이 가장 우아하다고 생각합니다. 컴파일러는이를 놓친 경우 알려줍니다. 어휘 범위 매개 변수 "outerThis"를 호출하는 규칙을 사용하지만 "self"또는 다른 이름이 더 좋을 수 있습니다.
"this"키워드의 사용은 OO 세계에서 빼앗 겼고 TypeScript가이를 채택했을 때 (내가 추정하는 ECMAScript 6 사양에서) 어휘 범위 개념과 동적 범위 개념을 결합했습니다. 다른 엔티티에서 메서드를 호출 할 때마다 . 나는 이것에 약간 불만이 있습니다. TypeScript에서 "self"키워드를 선호하여 어휘 범위가 지정된 개체 인스턴스를 넘길 수 있습니다. 또는 JS가 필요할 때 명시적인 첫 번째 위치 "호출자"매개 변수를 요구하도록 재정의 할 수 있습니다 (따라서 모든 웹 페이지를 한 번에 중단).
여기 내 해결책이 있습니다 (대규모 수업에서 제외됨). 특히 메서드가 호출되는 방식과 특히 "dragmoveLambda"본문을 살펴보십시오.
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 doesn't provide any extra way (beyond the regular JavaScript means) to get back to the 'real' this
reference other than this
remapping convenience provided in the fat arrow lambda syntax (which is allowable from a back-compat perspective since no existing JS code could be using a =>
expression).
You could post a suggestion to the CodePlex site, but from a language design perspective there's probably not much that can happen here, since any sane keyword the compiler could provide might already be in use by extant JavaScript code.
You can use js eval function: var realThis = eval('this');
I have faced a similar problem. I think you can use .each()
in many cases to keep this
as a different value for later events.
The JavaScript way:
$(':input').on('focus', function() {
$(this).css('background-color', 'green');
}).on('blur', function() {
$(this).css('background-color', 'transparent');
});
The TypeScript way:
$(':input').each((i, input) => {
var $input = $(input);
$input.on('focus', () => {
$input.css('background-color', 'green');
}).on('blur', () => {
$input.css('background-color', 'transparent');
});
});
I hope this helps someone.
You could store your reference to this
in another variable.. self
perhaps, and access the reference that way. I don't use typescript, but that's a method that's been successful for me with vanilla javascript in the past.
Check out this blog post http://lumpofcode.blogspot.com/2012/10/typescript-dart-google-web-toolkit-and.html, it has a detailed discussion of techniques for organizing calls within and across TypeScript classes.
There is much simpler solution than all the above answers. Basically we fall back to JavaScript by using key word function instead of using '=>' construct which will translate the 'this' into class 'this'
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
'Development Tip' 카테고리의 다른 글
VS2010 : 솔루션 탐색기에서 "외부 종속성"폴더를 제거하거나 숨기는 방법 (0) | 2020.10.23 |
---|---|
두 데이터베이스간에 외래 키 관계 추가 (0) | 2020.10.23 |
연결 문자열이 유효한지 확인하는 방법은 무엇입니까? (0) | 2020.10.23 |
데이터베이스 대 플랫 파일 (0) | 2020.10.23 |
다른 어셈블리의 클래스 이름에서 유형 확인 (0) | 2020.10.23 |