最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Why doesn't typescript use the 'self' trick? - Stack Overflow

programmeradmin0浏览0评论

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
  • 2 This is up to you, to the caller of the function. – elclanrs Commented Nov 25, 2014 at 8:55
  • Abandoning the prototype mechanism would make more unintuitive code. – Bergi Commented Nov 25, 2014 at 8:59
  • Why don't you try run(person.die.bind(person))? How do you expect TypeScript to know that when you type run(person.die), that it's meant to be compiled to run(person.die.bind(die)) and not run(person.die)? Remember, explicit is always better than implicit. – Aadit M Shah Commented Nov 25, 2014 at 8:59
  • @Bergi You could abandon object-orientation altogether and opt for pure functional code. – Aadit M Shah Commented Nov 25, 2014 at 9:01
  • 1 You could also fix the run function to accept a context argument: function run(delegate, context){ delegate.call(context); }, then run(person.die, person); – pawel Commented Nov 25, 2014 at 9:01
 |  Show 3 more comments

3 Answers 3

Reset to default 9

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.

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.

发布评论

评论列表(0)

  1. 暂无评论