Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't typescript use the 'self' trick?

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?

like image 278
Gilthans Avatar asked Nov 25 '14 08:11

Gilthans


2 Answers

You 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.

like image 74
Titian Cernicova-Dragomir Avatar answered Oct 03 '22 00:10

Titian Cernicova-Dragomir


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.

like image 44
Ross Scott Avatar answered Oct 02 '22 22:10

Ross Scott