Two primary reasons:
Change detection
$ ts-node
> import {BehaviorSubject} from "rxjs";
> import {distinctUntilChanged} from "rxjs/operators";
> import {clone} from "lodash";
> let s$ = new BehaviorSubject<number[]>([]);
> s$.subscribe(nv => console.log("raw " + JSON.stringify(nv)));
raw []
> s$.pipe(distinctUntilChanged()).subscribe(nv => console.log("duc " + JSON.stringify(nv)));
duc []
> s$.next([1]);
raw [1]
duc [1]
happy so far
> let nv = clone(s$.value); nv.push(2); s$.next(nv);
raw [1,2]
duc [1,2]
still cruising, but here comes the patch of black ice
> let xv = s$.value; xv.push(3); s$.next(xv);
raw [1,2,3]
…and crickets from the duc
subscription, because it can’t recognize anything as “changed” except the top-level reference.
Aliasing
$ ts-node
> import {BehaviorSubject} from "rxjs";
> let s$ = new BehaviorSubject<number[]>([]);
> let elsewhere: number[] = [];
> let sub1 = s$.subscribe(nv => elsewhere = nv);
> s$.next([1]);
> elsewhere;
[ 1 ]
So far, so good, but now we have aliased elsewhere
to the array buried deep within s$
.
> sub1.unsubscribe();
> elsewhere === s$.value;
true
ruh roh
> let v = s$.value;
> v.push(2);
> elsewhere;
[ 1, 2 ]
Well, customers$.next
is expecting an array, but Array.push
returns the array length (this is just an excuse for me to dunk on JavaScript some more…please don’t take it personally…it was totally clear what you meant). Hopefully the underlying question is addressed sufficiently above.