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