Angular 中自定義 toJSON 操做符

若是對 RxJS 的 operators (操做符) 不熟悉的話,建議讀者在閱讀本文時,先閱讀 RxJS - Observables, observers 和 operators 簡介 這篇文章。javascript

基礎知識

什麼是 Operator

Operator 是一個函數,它接收一個 Observable 對象,而後返回一個新的 Observable 對象。當咱們訂閱新返回的 Observable 對象時,它內部會自動訂閱前一個 Observable 對象。java

如何爲 Observable 添加操做符

比較常見的有如下三種方式:git

1.使用 ES7 函數綁定運算符 :: (可以使用 BabelJS 進行轉換)github

someObservable::mySimpleOperator(x => x + '!');

2.繼承 Observable 類,並重寫 lift() 方法typescript

class MyObservable extends Observable {
  lift(operator) {
    const observable = new MyObservable(); //<-- important part here
    observable.source = this;
    observable.operator = operator;
    return observable;
  }

  // put it here .. or ..
  customOperator() {
    /* do things and return an Observable */
  }
}

// ... put it here...
MyObservable.prototype.mySimpleOperator = mySimpleOperator;

3.直接添加到 Observable.prototype 對象上json

Observable.prototype.mySimpleOperator = mySimpleOperator;
someObservable.mySimpleOperator(x => x + '!');

自定義 toJSON 操做符

當咱們使用 Angular HTTP 服務時,咱們須要調用 Response 對象的 json() 方法把服務端接口返回的數據,轉換爲 JSON 對象,例如:bootstrap

this.http.get('https://api.github.com/orgs/angular/members?page=1&per_page=5')
    .map(res => res.json());

對於每一個接口,咱們都須要調用 map 操做符對返回的數據作對應的處理。那能不能簡化這個操做呢?答案是有的,咱們能夠經過自定義一個 toJSON 操做符來簡化上述的過程。具體實現以下:segmentfault

function toJSON<T>(): Observable<T> {
  return this.map(( response : Response ) => response.json());
}

上面代碼中,this 指向源 Observable 對象,即調用 http 對象的 get() 方法後返回的 Observable 對象。此外咱們直接返回了調用 map() 操做符後新建的 Observable 對象。api

爲了可以使用咱們自定義的 toJSON 操做符,咱們須要把它添加到 Observable 的原型對象上:babel

Observable.prototype.toJSON = toJSON;

最後的一件事是咱們須要添加如下的定義:

declare module "rxjs/Observable" {
  interface Observable<T> {
    toJSON : typeof toJSON;
  }
}

完整示例

custom-operators.ts

import { Observable } from 'rxjs/Observable';

function toJSON<T>(): Observable<T> {
  return this.map(( response : Response ) => response.json());
}

Observable.prototype.toJSON = toJSON;

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpModule } from "@angular/http";

import { AppComponent } from './app.component';
import './custom-operators';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.ts

import { Observable } from 'rxjs/Observable';
import { Component, OnInit } from '@angular/core';
import { Http } from '@angular/http'; 
import 'rxjs/add/operator/map'; 

interface Member {
    id: string;
    login: string;
    avatar_url: string;
}

@Component({
    selector: 'app-root',
    template: `
    <h3>Angular Orgs Members</h3>
    <ul *ngIf="members">
      <li *ngFor="let member of members;">
        <p>
          <img [src]="member.avatar_url" width="48" height="48"/>
          ID:<span>{{member.id}}</span>
          Name: <span>{{member.login}}</span>
        </p>
      </li>
    </ul>
    `
})
export class AppComponent implements OnInit {
  members: Member[];

  constructor(private http: Http) { } 

  ngOnInit() {
    this.http.get(`https://api.github.com/orgs/angular/members?page=1&per_page=5`) 
        .toJSON<Member[]>() // 使用自定義 toJSON 操做符
        .subscribe(data => {
           if (data) this.members = data; 
        });
    }
}

typings.d.ts

// src/typings.d.ts (在該文件下,新增如下內容)
export declare function toJSON<T>(): Observable<T>;

declare module "rxjs/Observable" {
  interface Observable<T> {
    toJSON : typeof toJSON;
  }
}

參考資源

相關文章
相關標籤/搜索