Я не уверен в лучшем подходе для обработки области видимости «этого» в TypeScript.
Вот пример общего шаблона в коде, который я конвертирую в TypeScript:
class DemonstrateScopingProblems {
private status = "blah";
public run() {
alert(this.status);
}
}
var thisTest = new DemonstrateScopingProblems();
// works as expected, displays "blah":
thisTest.run();
// doesn't work; this is scoped to be the document so this.status is undefined:
$(document).ready(thisTest.run);
Теперь я могу изменить звонок на ...
$(document).ready(thisTest.run.bind(thisTest));
... что действительно работает. Но это ужасно. Это означает, что весь код может компилироваться и работать нормально в некоторых обстоятельствах, но если мы забудем привязать область видимости, он сломается.
Мне нужен способ сделать это внутри класса, чтобы при использовании класса нам не нужно было беспокоиться о том, к чему относится «это».
Какие-либо предложения?
Обновить
Другой подход, который работает, - использование толстой стрелки:
class DemonstrateScopingProblems {
private status = "blah";
public run = () => {
alert(this.status);
}
}
Это правильный подход?
typescript
this
Джонатан Моффатт
источник
источник
Ответы:
У вас есть несколько вариантов, каждый со своими компромиссами. К сожалению, нет очевидного лучшего решения, и это действительно будет зависеть от приложения.
Автоматическая привязка классов
Как показано в вашем вопросе:
this
контекст вместо того, чтобы каждый сайт вызова создавал новое закрытие при вызове.this
контекст.super.
Function.bind
Также как показано:
Толстая стрелка
в TypeScript (показанная здесь с некоторыми фиктивными параметрами для пояснения):
источник
Другое решение, которое требует некоторой начальной настройки, но окупается своим непреодолимо легким синтаксисом буквально из одного слова, - это использование декораторов методов для JIT-связывания методов через геттеры.
Я создал репозиторий на GitHub, чтобы продемонстрировать реализацию этой идеи (это немного длинно, чтобы уместиться в ответ с его 40 строками кода, включая комментарии) , который вы могли бы использовать так же просто, как:
Я еще нигде не видел, чтобы это упоминалось, но работает безупречно. Кроме того, у этого подхода нет заметных недостатков: реализация этого декоратора - включая некоторую проверку типов для обеспечения безопасности типов во время выполнения - тривиальна и проста и требует практически нулевых накладных расходов после первоначального вызова метода.
Существенной частью является определение следующего получателя для прототипа класса, который выполняется непосредственно перед первым вызовом:
Полный исходный код
Идея также может быть продвинута на один шаг дальше, вместо этого выполняя это в декораторе класса, перебирая методы и определяя описанный выше дескриптор свойства для каждого из них за один проход.
источник
Некромантинг.
Есть очевидное простое решение, которое не требует стрелочных функций (стрелочные функции на 30% медленнее) или JIT-методов через геттеры.
Это решение - привязать этот контекст в конструкторе.
Вы можете написать метод autobind для автоматического связывания всех функций в конструкторе класса:
Обратите внимание: если вы не поместите функцию autobind в тот же класс, что и функцию-член, это просто,
autoBind(this);
а неthis.autoBind(this);
Кроме того, указанная выше функция autoBind упрощена, чтобы показать принцип.
Если вы хотите, чтобы это работало надежно, вам необходимо проверить, является ли функция также получателем / установщиком свойства, иначе - бум - если ваш класс содержит свойства, то есть.
Как это:
источник
Вы пытались изменить последнюю строку в своем коде следующим образом?
источник