Привет, Хабр! Представляю вашему вниманию перевод статьи «Что делать, когда «это» теряет контекст» автор Кристи Салческу .
Лучший способ не потерять контекст этот - не использовать этот .
Однако, это не всегда возможно.
Например, мы работаем с чужим кодом или библиотекой, использующей этот .
Литерал объекта, функция-конструктор, конструктор объектов класса в системе прототипов.
Псевдопараметр этот используется в системе прототипирования для предоставления доступа к свойствам объекта.
Давайте рассмотрим несколько случаев.
Вложенные функции
этот теряет ссылку на контекст внутри вложенных функций.
Метод сделай что-нибудь() две вложенные функции: сделатьДругое() И бревно() .class Service { constructor(){ this.numbers = [1,2,3]; this.token = "token"; } doSomething(){ setTimeout(function doAnotherThing(){ this.numbers.forEach(function log(number){ //Cannot read property 'forEach' of undefined console.log(number); console.log(this.token); }); }, 100); } } let service = new Service(); service.doSomething();
При звонке сервис.
doSomething() , этот теряет ссылку на контекст во вложенной функции.
связывать()
Одним из способов решения проблемы является метод связывать() .
Взгляните на следующий код: doSomething(){
setTimeout(function doAnotherThing(){
this.numbers.forEach(function log(number){
console.log(number);
console.log(this.token);
}.
bind(this)); }.
bind(this), 100);
}
связывать() создает новую версию функции, которая при вызове уже имеет определенное значение этот .
функция doAnotherThing(){ /*…*/}.
bind(this) создает версию функции сделатьДругуюВещь() , который принимает значение этот от сделай что-нибудь() .
это/я
Другой вариант — объявить и использовать новую переменную.это/я , который будет хранить значение этот из метода сделай что-нибудь() .
doSomething(){
let that = this;
setTimeout(function doAnotherThing(){
that.numbers.forEach(function log(number){
console.log(number);
console.log(that.token);
});
}, 100);
}
Мы должны объявить пусть это = это во всех методах с использованием этот во вложенных функциях.
Стрелочные функции
Стрелочная функция дает нам еще один способ решить эту проблему.
doSomething(){
setTimeout(() => {
this.numbers.forEach(number => {
console.log(number);
console.log(this.token);
});
}, 100);
}
Стрелочные функции не создают собственный контекст для этот , но используйте значение этот окружающий контекст. В приведенном выше примере она использует значение этот родительская функция.
Недостаток этого метода в том, что мы не можем указать имя стрелочной функции.
Имя функции важно, поскольку оно повышает читаемость кода и описывает ее назначение.
Ниже приведен тот же код с функцией, выраженной через имя переменной: doSomething(){
let log = number => {
console.log(number);
console.log(this.token);
}
let doAnotherThing = () => {
this.numbers.forEach(log);
}
setTimeout(doAnotherThing, 100);
}
Метод как обратный вызов
этот теряет ссылку на контекст при использовании метода в качестве функции обратного вызова.
Давайте посмотрим на следующий класс: class Service {
constructor(){
this.token = "token";
}
doSomething(){
console.log(this.token);//undefined
}
}
let service = new Service();
Давайте рассмотрим ситуации, в которых метод сервис.
doSomething() используется как функция обратного вызова.
//callback on DOM event
$("#btn").
click(service.doSomething);
//callback for timer
setTimeout(service.doSomething, 0);
//callback for custom function
run(service.doSomething);
function run(fn){
fn();
}
Во всех случаях выше этот теряет связь с контекстом.
связывать()
Мы можем использовать связывать() Для решения этой проблемы.
Ниже приведен код этой опции: //callback on DOM event
$("#btn").
click(service.doSomething.bind(service));
//callback for timer
setTimeout(service.doSomething.bind(service), 0);
//callback for custom function
run(service.doSomething.bind(service));
Стрелочная функция
Другой способ — создать стрелочную функцию, которая вызывает сервис.doSomething() .
//callback on DOM event
$("#btn").
click(() => service.doSomething());
//callback for timer
setTimeout(() => service.doSomething(), 0);
//callback for custom function
run(() => service.doSomething());
Реагировать на компоненты
В компонентах этот теряет ссылку на контекст, когда методы используются в качестве обратных вызовов для событий.
class TodoAddForm extends React.Component {
constructor(){
super();
this.todos = [];
}
componentWillMount() {
this.setState({desc: ""});
}
add(){
let todo = {desc: this.state.desc};
//Cannot read property 'state' of undefined
this.todos.push(todo);
}
handleChange(event) {
//Cannot read property 'setState' of undefined
this.setState({desc: event.target.value});
}
render() {
return <form>
<input onChange={this.handleChange} value={this.state.desc} type="text"/>
<button onClick={this.add} type="button">Save</button>
</form>;
}
}
ReactDOM.render(
<TodoAddForm />,
document.getElementById('root'));
В качестве решения мы можем создать в конструкторе новые функции, которые будут использовать связать (это) .
constructor(){
super();
this.todos = [];
this.handleChange = this.handleChange.bind(this);
this.add = this.add.bind(this);
}
Не используйте «это»
Нет этот - нет проблем с потерей контекста.Объекты можно создавать с помощью заводские функции .
Посмотрите на этот пример: function Service() {
let numbers = [1,2,3];
let token = "token";
function doSomething(){
setTimeout(function doAnotherThing(){
numbers.forEach(function log(number){
console.log(number);
console.log(token);
});
}, 100);
}
return Object.freeze({
doSomething
});
}
Контекст сохраняется, если вы используете метод в качестве обратного вызова.
let service = Service();
service.doSomething();
//callback on DOM event
$("#btn").
click(service.doSomething);
//callback for timer
setTimeout(service.doSomething, 0);
//callback for custom function
run(service.doSomething);
Заключение
этот теряет связь с контекстом в различных ситуациях.связывать() , использование переменных это/я а стрелочные функции — это способы решения проблем с контекстом.
Фабричные функции позволяют создавать объекты без использования этот .
Теги: #JavaScript #context #this[]
-
Смит, Саймон
19 Oct, 24 -
Как Выбрать Тексты Sapscript В Cds
19 Oct, 24 -
Как «Звучит» Космос?
19 Oct, 24 -
Каратель Мороженого!
19 Oct, 24 -
Карманные Компьютеры: Где Прогресс?
19 Oct, 24