2014-11-25 5 views
3

Я написал следующий код Машинопись:Почему не машинопись не использует трюк «сам»?

class Person { 
    constructor(public firstname: string, public lastname:string){ 
} 

public die(){ 
    this.lastname += " RIP"; 
} 

И это компилируется:

var Person = (function() { 
    function Person(firstname, lastname) { 
     this.firstname = firstname; 
     this.lastname = lastname; 
    } 

    Person.prototype.die = function() { 
     this.lastname += " RIP"; 
    }; 
    return Person; 
})(); 

Что, конечно, является правильным способом, но это не будет работать, как ожидается, в следующем случае:

function run(delegate){ 
    delegate(); 
} 

var person = new Person("guy", "dude"); 
run(person.die); 
alert(person.lastname); 
alert(lastname); 

Ожидаемые предупреждения здесь будут «dude RIP», а затем «undefined». Однако фактическим результатом будет «чувак» и «неопределенный RIP». Это связано с тем, что этот параметр работает в JS странно.

Обычное решение, который должен использовать переменный само замыкание, и отказаться от механизма прототипа, т.е.

var Person = (function() { 
    function Person(firstname, lastname) { 
     var self = this; 
     self.firstname = firstname; 
     self.lastname = lastname; 
     self.die = function() { 
      self.lastname += " RIP"; 
     } 
    } 
    return Person; 
})(); 

Какого будет работать, как ожидалось. Что является преимуществом этого конкретного способа компиляции кода? Разписал ли машинопись о том, чтобы оставить этот кусок неинтуитивного кода?

+2

Это зависит от вас, от вызывающей функции. – elclanrs

+0

Отказ от механизма прототипа сделает более неинтуитивный код. – Bergi

+0

Почему бы вам не попробовать 'run (person.die.bind (person))'? Как вы ожидаете, что TypeScript узнает, что при вводе 'run (person.die)' он должен быть скомпилирован для 'run (person.die.bind (die))', а не 'run (person.die)' ? Помните, что [явный всегда лучше, чем неявный] (http://legacy.python.org/dev/peps/pep-0020/). –

ответ

7

Вы должны изменить структуру кода немного, чтобы заставить его использовать _this = this шаблон:

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; 
})(); 

Ключевой частью является то, что вам необходимо поместить кубик функции на объекте, а не прототипе, который заставляет его использовать _this = this.

+5

Таким образом, я могу решить, когда я хочу использовать этот шаблон, а когда нет. Благодаря! Я также обнаружил, почему использование прототипа предпочтительнее использования этого метода. Таким образом, каждый объект имеет копию функции, что приводит к увеличению объема памяти. Используя прототипы, каждый объект более тонкий. Благодаря! – Gilthans

3

Вы должны использовать синтаксис функции стрелки, когда хотите ее захватить. Я думаю, что было бы лучше использовать это при создании делегата вместо создания класса.

Единственное изменение необходимо было бы:

run(()=>person.die()); 

Это позволяет захватывать это для любой функции независимо от того, как она была определена.

+0

Это ПУТЬ лучше, чем принятый ответ, который является скорее взломом. –

Смежные вопросы