I wrote the following TypeScript code:
class Person {
constructor(public firstname: string, public lastname:string){
}
public die(){
this.lastname += " RIP";
}
And this compiles to:
var Person = (function() {
function Person(firstname, lastname) {
this.firstname = firstname;
this.lastname = lastname;
}
Person.prototype.die = function () {
this.lastname += " RIP";
};
return Person;
})();
Which of course is a valid way, but it will not work as expected in the following case:
function run(delegate){
delegate();
}
var person = new Person("guy", "dude");
run(person.die);
alert(person.lastname);
alert(lastname);
The expected alerts here would be "dude RIP", and then "undefined". However, the actual result would be "dude" and "undefined RIP". This is because the this parameter works strangely in JS.
A common solution to that is to use a self variable by closure, and to abandon the prototype mechanism, i.e.
var Person = (function() {
function Person(firstname, lastname) {
var self = this;
self.firstname = firstname;
self.lastname = lastname;
self.die = function() {
self.lastname += " RIP";
}
}
return Person;
})();
Which would work as expected. What is advantage of that specific way to compile code? Did typescript decide to leave that piece of unintuitive code?
I wrote the following TypeScript code:
class Person {
constructor(public firstname: string, public lastname:string){
}
public die(){
this.lastname += " RIP";
}
And this compiles to:
var Person = (function() {
function Person(firstname, lastname) {
this.firstname = firstname;
this.lastname = lastname;
}
Person.prototype.die = function () {
this.lastname += " RIP";
};
return Person;
})();
Which of course is a valid way, but it will not work as expected in the following case:
function run(delegate){
delegate();
}
var person = new Person("guy", "dude");
run(person.die);
alert(person.lastname);
alert(lastname);
The expected alerts here would be "dude RIP", and then "undefined". However, the actual result would be "dude" and "undefined RIP". This is because the this parameter works strangely in JS.
A common solution to that is to use a self variable by closure, and to abandon the prototype mechanism, i.e.
var Person = (function() {
function Person(firstname, lastname) {
var self = this;
self.firstname = firstname;
self.lastname = lastname;
self.die = function() {
self.lastname += " RIP";
}
}
return Person;
})();
Which would work as expected. What is advantage of that specific way to compile code? Did typescript decide to leave that piece of unintuitive code?
Share Improve this question asked Nov 25, 2014 at 8:53 GilthansGilthans 1,7262 gold badges18 silver badges24 bronze badges 8 | Show 3 more comments3 Answers
Reset to default 9You should use the arrow function syntax when you want to capture this. I think it would be better to use this at the sight of delegate creation instead of class creation.
The only change needed would be:
run(()=>person.die());
This allows you to capture this for any function regardless of how it was defined.
You need to change the structure of your code slightly to get it to use the _this = this
pattern:
class Person {
constructor(public firstName: String, public lastName: String) {
}
die = () => {
this.lastName += "dead"
}
}
Becomes:
var Person = (function () {
function Person(firstName, lastName) {
var _this = this;
this.firstName = firstName;
this.lastName = lastName;
this.die = function () {
_this.lastName += "dead";
};
}
return Person;
})();
The key part is that you need to place the die function on the object not the prototype, which forces it to use _this = this
.
Because that is how classes in JS works. Typescript devs decided they didn't want to change any pre existing features of the lang.
run(person.die.bind(person))
? How do you expect TypeScript to know that when you typerun(person.die)
, that it's meant to be compiled torun(person.die.bind(die))
and notrun(person.die)
? Remember, explicit is always better than implicit. – Aadit M Shah Commented Nov 25, 2014 at 8:59run
function to accept a context argument:function run(delegate, context){ delegate.call(context); }
, thenrun(person.die, person);
– pawel Commented Nov 25, 2014 at 9:01