admin管理员组

文章数量:1023045

How can Observable class be extended by applying built-in RxJS operators to it?

I would like to do something like this:

class TruthyObservable extends Observable {
  constructor(subscriber) {
    super(subscriber);

    return this.filter(x => x);
  }
}

class TruthyMappedObservable extends TruthyObservable {
  constructor(subscriber) {
    super(subscriber);

    return this.map(x => `'${x}'`);
  }
}

Can this be done without constructor return?

How can Observable class be extended by applying built-in RxJS operators to it?

I would like to do something like this:

class TruthyObservable extends Observable {
  constructor(subscriber) {
    super(subscriber);

    return this.filter(x => x);
  }
}

class TruthyMappedObservable extends TruthyObservable {
  constructor(subscriber) {
    super(subscriber);

    return this.map(x => `'${x}'`);
  }
}

Can this be done without constructor return?

Share Improve this question edited Dec 28, 2016 at 19:57 Estus Flask asked Dec 28, 2016 at 17:29 Estus FlaskEstus Flask 224k79 gold badges472 silver badges613 bronze badges 4
  • Where do you expect the .filter(x => x); to be added? I'd understand it if you were trying to always append a standard RxJS operator to your custom operator. – martin Commented Dec 28, 2016 at 17:57
  • @martin I expect that the operator will be added on class instantiation, before any other operator. – Estus Flask Commented Dec 28, 2016 at 18:02
  • An operator is not a class which extends Rx.Observable. It's a method on its prototype. Anyway, I guess you meant this.filter(Boolean)? – user663031 Commented Dec 28, 2016 at 19:36
  • @torazaburo Yes. The question isn't limited to filter though, it's there for example. – Estus Flask Commented Dec 28, 2016 at 19:44
Add a ment  | 

2 Answers 2

Reset to default 3

This pretty much depends on what you want to do but let's say you want to make a TruthyObservable that behaves very much like the default Observable.create(...) but passes only even numbers:

import { Observable, Observer, Subscriber, Subject, Subscription } from 'rxjs';
import 'rxjs/add/operator/filter';

class TruthyObservable<T> extends Observable<T> {

    constructor(subscribe?: <R>(this: Observable<T>, subscriber: Subscriber<R>) => any) {
        if (subscribe) {
            let oldSubscribe = subscribe;
            subscribe = (obs: Subscriber<any>) => {
                obs = this.appendOperators(obs);
                return oldSubscribe.call(this, obs);
            };
        }

        super(subscribe);
    }

    private appendOperators(obs: Subscriber<any>) {
        let subject = new Subject();

        subject
            .filter((val: number) => val % 2 == 0)
            .subscribe(obs);

        return new Subscriber(subject);
    }

}

let o = new TruthyObservable<number>((obs: Observer<number>) => {
    obs.next(3);
    obs.next(6);
    obs.next(7);
    obs.next(8);
});

o.subscribe(val => console.log(val));

This prints to console:

6
8

See live demo: https://jsbin./recuto/3/edit?js,console

Usually classes inheriting Observable override the _subscribe() method that actually makes the subscription internally but in ours case we want to use the callback where we can emit values by ourselves (since this Observable doesn't emit anything itself). Method _subscribe() is overshadowed by _subscribe property if it exists so we wouldn't be able to append any operators to it if we just overrode this method. That's why I wrap _subscribe in the constructor with another function and then pass all values through a Subject chained with filter() in appendOperators() method. Note that I replaced the original Observer with the Subject at obs = this.appendOperators(obs).

At the end when I call eg. obs.next(3); I'm in fact pushing values to the Subject that filters them and passes them to the original Observer.

I think you can get what you need with custom operator:

    Observable.prototype.truthy = function truthy() {
        return this.filter(x => x);
    }

How can Observable class be extended by applying built-in RxJS operators to it?

I would like to do something like this:

class TruthyObservable extends Observable {
  constructor(subscriber) {
    super(subscriber);

    return this.filter(x => x);
  }
}

class TruthyMappedObservable extends TruthyObservable {
  constructor(subscriber) {
    super(subscriber);

    return this.map(x => `'${x}'`);
  }
}

Can this be done without constructor return?

How can Observable class be extended by applying built-in RxJS operators to it?

I would like to do something like this:

class TruthyObservable extends Observable {
  constructor(subscriber) {
    super(subscriber);

    return this.filter(x => x);
  }
}

class TruthyMappedObservable extends TruthyObservable {
  constructor(subscriber) {
    super(subscriber);

    return this.map(x => `'${x}'`);
  }
}

Can this be done without constructor return?

Share Improve this question edited Dec 28, 2016 at 19:57 Estus Flask asked Dec 28, 2016 at 17:29 Estus FlaskEstus Flask 224k79 gold badges472 silver badges613 bronze badges 4
  • Where do you expect the .filter(x => x); to be added? I'd understand it if you were trying to always append a standard RxJS operator to your custom operator. – martin Commented Dec 28, 2016 at 17:57
  • @martin I expect that the operator will be added on class instantiation, before any other operator. – Estus Flask Commented Dec 28, 2016 at 18:02
  • An operator is not a class which extends Rx.Observable. It's a method on its prototype. Anyway, I guess you meant this.filter(Boolean)? – user663031 Commented Dec 28, 2016 at 19:36
  • @torazaburo Yes. The question isn't limited to filter though, it's there for example. – Estus Flask Commented Dec 28, 2016 at 19:44
Add a ment  | 

2 Answers 2

Reset to default 3

This pretty much depends on what you want to do but let's say you want to make a TruthyObservable that behaves very much like the default Observable.create(...) but passes only even numbers:

import { Observable, Observer, Subscriber, Subject, Subscription } from 'rxjs';
import 'rxjs/add/operator/filter';

class TruthyObservable<T> extends Observable<T> {

    constructor(subscribe?: <R>(this: Observable<T>, subscriber: Subscriber<R>) => any) {
        if (subscribe) {
            let oldSubscribe = subscribe;
            subscribe = (obs: Subscriber<any>) => {
                obs = this.appendOperators(obs);
                return oldSubscribe.call(this, obs);
            };
        }

        super(subscribe);
    }

    private appendOperators(obs: Subscriber<any>) {
        let subject = new Subject();

        subject
            .filter((val: number) => val % 2 == 0)
            .subscribe(obs);

        return new Subscriber(subject);
    }

}

let o = new TruthyObservable<number>((obs: Observer<number>) => {
    obs.next(3);
    obs.next(6);
    obs.next(7);
    obs.next(8);
});

o.subscribe(val => console.log(val));

This prints to console:

6
8

See live demo: https://jsbin./recuto/3/edit?js,console

Usually classes inheriting Observable override the _subscribe() method that actually makes the subscription internally but in ours case we want to use the callback where we can emit values by ourselves (since this Observable doesn't emit anything itself). Method _subscribe() is overshadowed by _subscribe property if it exists so we wouldn't be able to append any operators to it if we just overrode this method. That's why I wrap _subscribe in the constructor with another function and then pass all values through a Subject chained with filter() in appendOperators() method. Note that I replaced the original Observer with the Subject at obs = this.appendOperators(obs).

At the end when I call eg. obs.next(3); I'm in fact pushing values to the Subject that filters them and passes them to the original Observer.

I think you can get what you need with custom operator:

    Observable.prototype.truthy = function truthy() {
        return this.filter(x => x);
    }

本文标签: javascriptExtend RxJS Observable class with operatorsStack Overflow