web-dev-qa-db-fra.com

Les variables d'accès ont déclaré un composant à partir d'une fonction subscribe () de RxJS

Je peux utiliser this.variable Pour accéder aux variables dans n'importe quelle partie du composant, sauf à l'intérieur des fonctions RxJS comme subscribe() ou catch().

Dans l'exemple ci-dessous, je souhaite imprimer un message après avoir exécuté un processus:

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

Lorsque j'exécute doSomething(), j'obtiens non défini. Ce scénario peut être résolu à l'aide d'une variable locale:

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

Je suppose que cela est lié au this, cependant, pourquoi je ne peux pas accéder au this.message À l'intérieur de la subscribe()?

13
Haoliang Yu

Cela n'a rien à voir avec rx ou angulaire, et tout à voir avec Javascript et TypeScript.

Je suppose que vous connaissez la sémantique de this dans le contexte des invocations de fonctions en Javascript (sinon, il y a les explications ne manquent pas en ligne ) - ces sémantiques s'appliquent dans le premier extrait de code, bien sûr, et c'est la seule raison pour laquelle this.message n'est pas défini dans subscribe(). C'est juste Javascript.

Puisque nous parlons de TypeScript: les fonctions fléchées sont une construction TypeScript destinée (en partie) à contourner la maladresse de ces sémantiques en capturant lexicalement la signification de this, ce qui signifie que this à l'intérieur d'une fonction flèche === this à partir du contexte externe.

Donc, si vous remplacez:

.subscribe(function(location) {
        //this != this from outer context 
        console.log(this.message); //prints 'undefined'
    });

par:

.subscribe((location) => {
     //this == this from the outer context 
        console.log(this.message); //prints 'success'
    });

Vous obtiendrez le résultat attendu.

36
drew moore

Comme alternative à la réponse de @ drewmoore, si vous souhaitez avoir des fonctions externes, vous pouvez faire:

 .subscribe((location) => dataHandler(location), (error) => errorHandler(error));

 ....

 const dataHandler = (location) => {
     ...
 }

En externalisant la fonction errorHandler, elle peut être utilisée à plusieurs endroits (c'est-à-dire des abonnements). En ayant des fonctions de flèche (grasse), votre code capturera le contexte "ce" (comme expliqué dans la réponse de @ Drewmoore).

Ce qui manque, c'est la capacité à écrire ce qui suit et à gérer comme une fonction de flèche. Ce qui suit fonctionne et passe implicitement l'argument. Malheureusement AFAIK, vous ne pouvez pas capturer le contexte this (peut-être utiliser bind pour y parvenir, bien que cela rend le code plus verbeux dans l'ensemble).

 .subscribe(dataHandler, errorHandler);

C'est tellement succinct! Mais hélas ne fonctionnera pas si le contexte est requis.

1
HankCa