Переменные доступа, объявленные компонентом из функции subscribe() RxJS
Я могу использовать this.variable
для доступа к переменным в любой части компонента, кроме как внутри функций RxJS, таких как subscribe()
или catch()
.
В приведенном ниже примере я хочу напечатать сообщение после запуска процесса:
import {Component, View} from 'angular2/core';
@Component({
selector: 'navigator'
})
@View({
template: './app.component.html',
styles: ['./app.component.css']
})
export class AppComponent {
message: string;
constructor() {
this.message = 'success';
}
doSomething() {
runTheProcess()
.subscribe(function(location) {
console.log(this.message);
});
}
}
Когда я запускаю doSomething()
, я получаю неопределенное значение. Этот сценарий может быть решен с использованием локальной переменной:
import {Component, View} from 'angular2/core';
@Component({
selector: 'navigator'
})
@View({
template: './app.component.html',
styles: ['./app.component.css']
})
export class AppComponent {
message: string;
constructor() {
this.message = 'success';
}
doSomething() {
// assign it to a local variable
let message = this.message;
runTheProcess()
.subscribe(function(location) {
console.log(message);
});
}
}
Я предполагаю, что это связано с this
, однако, почему я не могу получить доступ к this.message
внутри subscribe()
?
Ответы
Ответ 1
Это не имеет никакого отношения к rx или angular, и все, что связано с Javascript и Typescript.
Я предполагаю, что вы знакомы с семантикой this
в контексте вызовов функций в Javascript (если нет, нет недостатка в объяснениях в Интернете) - Разумеется, эти семантики применяются в первом фрагменте, и единственная причина this.message
- undefined внутри subscribe()
. Это просто Javascript.
Поскольку мы говорим о Typescript:
Функции стрелок представляют собой конструкцию Typescript, предназначенную (частично), чтобы обойти неуклюжесть этой семантики путем лексического захвата значения this
, что означает, что this
внутри функция стрелки === this
из внешнего контекста.
Итак, если вы замените:
.subscribe(function(location) {
//this != this from outer context
console.log(this.message); //prints 'undefined'
});
:
.subscribe((location) => {
//this == this from the outer context
console.log(this.message); //prints 'success'
});
Вы получите ожидаемый результат.
Ответ 2
В качестве альтернативы ответу @drewmoore, если вы хотите иметь внешние функции, вы можете сделать:
.subscribe((location) => dataHandler(location), (error) => errorHandler(error));
....
const dataHandler = (location) => {
...
}
Внешняя функция errorHandler
может использоваться в нескольких местах (например, в подписках). Используя функции стрелок as (жирный), ваш код будет захватывать контекст this (как обсуждалось в ответе @Drewmoore).
Чего не хватает, так это умения написать следующее и обработать как функцию стрелки. Следующее работает и передает аргумент неявно. К сожалению, AFAIK, вы не можете охватить this
контекст (возможно, используйте bind
для достижения этого, хотя это делает код более многословным в целом).
.subscribe(dataHandler, errorHandler);
Это тааак лаконично! Но, увы, не будет работать, если требуется контекст.