Мне было интересно, как выглядит карта как на rxjs, так и на массиве. В чем различия между использованием метода карты массива и оператора карты rxjs?
Array.map
преобразует каждый элемент одного массива.
console.log( [ 1, 2, 3 ].map(x => x * x) )
// log: [ 1, 4, 9 ]
В целом, RXJS Observables больше похожи на поток данных, но каждый из них является его собственным объектом.
Вы можете хранить массивы в Observable, но все же каждый массив обрабатывается как отдельный объект. Каждый раз, когда вы вызываете Subject#next
, вы предоставляете совершенно новый массив. В этом случае нет эквивалента Array#push
с RXJS, потому что RXJS не заботится о том, что содержимое Observable оказывается массивом.
// Observable that holds an array as its type
const subject: Subject<number[]> = new Subject<number[]>();
subject.pipe(
// the value here is a full array
map(arr => arr.map(x => x * x))
).subscribe(arr => console.log(arr));
subject.next([ 1, 2, 3 ]);
// log: [ 1, 4, 9 ]
subject.next([ 7, 8, 9 ]);
// log: [ 49, 64, 81 ]
* Бонус: вы можете сделать что-то более похожее на массив, если вы настроите ReplaySubject
. Эта реализация Subject
буквально повторяет все данные, которые ему были предоставлены (или подмножество, основанное на том, как вы его создаете). Как вы увидите, ограничение на это будет заключаться в том, что вы можете только нажать на конец, и вам нужно создать новую подписку, чтобы увидеть весь "массив", но тем не менее это интересный мысленный эксперимент.
const subject: ReplaySubject<number> = new ReplaySubject<number>();
subject.next(1);
subject.next(2);
subject.next(3);
const transformed: Observable<number> = subject.pipe(
map(x => x * x)
);
transformed.pipe(first()).subscribe(x => console.log(x));
// log: 1
// log: 4
// log: 9
subject.next(9);
transformed.pipe(first()).subscribe(x => console.log(x));
// log: 1
// log: 4
// log: 9
// log: 81
Их функционирование совершенно одинаково, они дают новый массив/наблюдаемый (соответственно) с каждым элементом, преобразованным в соответствии с (обычно) функцией преобразования (имя технической компьютерной науки будет проекцией), принимая в качестве параметра модифицированный объект и его индекс,
Array.map
является частью прототипа массива изначально. Вы можете использовать его в любом массиве в любой среде JavaScript. (при условии, что вы не испортили Array.prototype, конечно)
Observable.map
необходимо импортировать. (Для RxJS 6: import { map } from 'rxjs/operators';
для более старых версий: import { map } from 'rxjs/add/operator/map'
Array.map
преобразования Array.map
имеет доступ ко всему преобразованному массиву (третий параметр в функции проецирования).
Пример:
let arr = ['a', 'b', 'c'];
let arrResult = arr.map(
(elem, index, wholeArray) => 'element ' + elem + ' was in position ' + index + ' in array ' + wholeArray);
console.log(arrResult);
Это "конечно" невозможно (вообще говоря) в контексте Наблюдаемого, поскольку "весь список" испускаемого значения, вероятно, не известен в момент выхода каждого элемента.
Напротив, существует еще одна небольшая разница: оператор Observable.map
принимает (необязательный) параметр thisArg
, поэтому функция преобразования имеет доступ к определенному контексту.
Я думаю, что это другое отличие довольно незначительно: Array.map
не нуждается в этом, потому что это функция, и вы также можете указать свое собственное " this
" с различными способами вызова функций в JavaScript. (Я не нашел хорошую ссылку для этой части, любой, кто хочет добавить ссылку на это в этом ответе, приветствуется).
Кроме того, в любом случае, я бы нашел интересным, чтобы его оспаривали в этом последнем пункте.
RxJS предназначен для работы с Observables
а встроенная map
- для Arrays
. Это единственное различие, о котором я могу думать.
.map
в RxJS, но это само по себе очень общее понятие. Он вообще не создается с массивами JS или JS - функция отображения всегда принимает входные данные типа A и производит выходные данные типа A или B (int -> int дляx => x*1
или int -> string дляx => "My number is: " + x
). В других контекстах у вас может быть контейнер для одного объекта, и вы используетеcontainer.map()
для взаимодействия и изменения базового значения (например, Java Optional), или вы можете использовать.map
в массиве, чтобы изменить все значения. Это та же идея, хотя.