TypeScript中是否存在"this"的别名?

Tod*_*odd 73 jquery typescript

我试图在TypeScript中编写一个类,该类具有一个定义的方法,该方法充当jQuery事件的事件处理程序回调.

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.
    }
}
Run Code Online (Sandbox Code Playgroud)

在onFocusIn事件处理程序中,TypeScript将"this"视为该类的"this".但是,jQuery会覆盖此引用并将其设置为与事件关联的DOM对象.

另一种方法是在构造函数中将lambda定义为事件处理程序,在这种情况下,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.
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

我的问题是,是否有另一种方法来使用TypeScript在基于方法的事件处理程序中访问此引用,以克服此jQuery行为?

Fen*_*ton 98

this使用箭头函数语法时保留范围() => { ... }- 这是一个取自TypeScript For JavaScript Programmers的示例.

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

需要注意的是this.text给你Text from outer function,因为箭头函数语法保留了"词法范围".

  • 这很棒.道具!这背后的做法是在方法的顶部创建一个`var _this = this`,然后在匿名函数中引用`_this`. (9认同)

Ste*_*man 21

因此,如上所述,没有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. 
    } 
} 
Run Code Online (Sandbox Code Playgroud)

这是一个合理的解决方案,但我个人发现开发人员经常忘记包含代理调用,所以我想出了一个基于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({});
Run Code Online (Sandbox Code Playgroud)

  • 我认为您的回答可能会产生误导,因为它给我的印象是TypeScript不支持这一点,而实际上如果您只是使用箭头语法定义您的方法. (3认同)

Sam*_*Sam 20

正如其他一些答案所述,使用箭头语法定义函数会导致引用this始终引用封闭类.

所以回答你的问题,这里有两个简单的解决方法.

使用箭头语法引用该方法

constructor(public id: string) {
    this.textarea = $(id);
    this.textarea.focusin(e => this.onFocusIn(e));
}
Run Code Online (Sandbox Code Playgroud)

使用箭头语法定义方法

onFocusIn = (e: JQueryEventObject) => {
    var height = this.textarea.css('height');
}
Run Code Online (Sandbox Code Playgroud)


Dre*_*kes 6

您可以将成员函数绑定到构造函数中的实例.

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
    }
}
Run Code Online (Sandbox Code Playgroud)

或者,只需在添加处理程序时绑定它.

        this.textarea.focusin(onFocusIn.bind(this));
Run Code Online (Sandbox Code Playgroud)