Another issue I bumped into was converting closures to TypeScript classes, ‘this’ again popped up as part of a larger issue. For example, starting with the following Javascript code
var MyNamespace = MyNamespace || {};
MyNamespace.Widget1 = function(inp,a,b)
{
var _a = a;
var _b = b;
var _inp = inp;
this.create = function()
{
inp.addEventListener("keydown",this.click);
}
this.click = function(e)
{
alert("clicked " + _a);
}
}
I converted it to the following TypeScript.
module MyNamespace
{
export class Widget1
{
private inp : HTMLElement;
private _a : number;
private _b : number;
constructor(inp:HTMLElement,a:number,b:number)
{
this._a = a;
this._b = b;
this.inp = inp;
}
public create()
{
this.inp.addEventListener("keydown",this.click);
}
private click(e)
{
alert("clicked " + this._a);
}
}
}
But this has a problem, I’ve converted a closure style object to a prototype style (what a TypeScript class is converted to) as can be seen here in the generated Javascript:
var MyNamespace;
(function (MyNamespace) {
var Widget1 = (function () {
function Widget1(inp, a, b) {
this._a = a;
this._b = b;
this.inp = inp;
}
Widget1.prototype.create = function () {
this.inp.addEventListener("keydown", this.click);
};
Widget1.prototype.click = function (e) {
alert("clicked " + this._a);
};
return Widget1;
})();
MyNamespace.Widget1 = Widget1;
})(MyNamespace || (MyNamespace = {}));
Using prototype in of itself is of course not a problem. However, since I changed my variables to be properties of ‘this’, a bug is born: ‘this’ in an event handler refers to the object that fired the event (in most browsers), not my object. Therefore the reference to ‘this._a’ refers to a most likely nonexistent property ‘_a’ on the DOM object that fired the event. We need to fix this by calling bind on the event handler function and getting a reference to a function that is bound to the correct ‘this’, like so
module MyNamespace
{
export class Widget1
{
private inp : HTMLElement;
private _a : number;
private _b : number;
constructor(inp:HTMLElement,a:number,b:number)
{
this._a = a;
this._b = b;
this.inp = inp;
}
public create()
{
// use bind to set this to the instance of Widget1 object not the object firing the event
var click = this.click.bind(this);
this.inp.addEventListener("keydown",click);
}
private click(e)
{
alert("clicked " + this._a);
}
}
}
OR
LOGIN OR REGISTER
Registered users with one approved comment can comment without moderation