Angular5中RxJS原型链机制及分离式操作符导入问题
关于Angular 5中RxJS分离导入操作符的问题解析
我来帮你把这个RxJS导入的坑给捋清楚,这在Angular 5(对应RxJS 5.x版本)里确实是个容易搞混的点!
为什么第一种导入方式会报错?
你用的第一种写法:
import { fromPromise } from 'rxjs/observable/fromPromise'; import { map } from 'rxjs/operator/map'; // 报错:fromPromise(...).map is not a function fromPromise(Promise.resolve('test')).map(val => val);
问题出在这种导入方式是「独立导入」,没有修改Observable的原型链:
fromPromise是独立的创建函数,返回的是一个Observable实例,但这个实例的原型上并没有map方法- 你导入的
map只是一个普通的函数,不是挂载在Observable原型上的方法,所以实例没法直接链式调用.map()
如果非要用这种独立导入的方式,得手动用call来绑定上下文:
import { fromPromise } from 'rxjs/observable/fromPromise'; import { map } from 'rxjs/operator/map'; const obs = fromPromise(Promise.resolve('test')); const mappedObs = map.call(obs, val => val.toUpperCase()); mappedObs.subscribe(console.log); // 输出 TEST
第二种导入方式的逻辑是什么?
第二种写法是RxJS 5.x里最常用的「补丁式导入」:
import { Observable } from 'rxjs/Observable'; import 'rxjs/add/observable/fromPromise'; // 给Observable静态对象加fromPromise方法 import 'rxjs/add/operator/map'; // 给Observable原型加map方法 // 正常链式调用 Observable.fromPromise(Promise.resolve('test')) .map(val => val.toUpperCase()) .subscribe(console.log);
这种导入的核心逻辑是修改原型链:
rxjs/add/observable/fromPromise模块内部会把fromPromise挂载到Observable类的静态属性上,所以你能通过Observable.fromPromise()调用rxjs/add/operator/map模块内部会把map函数挂载到Observable.prototype上,这样所有Observable实例都能通过原型链继承到.map()方法,自然就能链式调用了
Angular 5中RxJS的原型链工作原理
RxJS 5.x采用的是原型扩展的设计思路:
- 核心的
Observable类本身只提供最基础的功能 - 每个操作符(比如map、filter)和创建方法(比如fromPromise、of)都作为独立模块存在
- 当你导入
rxjs/add/xxx这类模块时,模块内部会执行类似这样的代码:// 以map为例 import { Observable } from '../../Observable'; import { map } from '../../operator/map'; Observable.prototype.map = map; - 这样一来,所有后续创建的Observable实例,都能通过原型链访问到这些扩展的方法,实现链式调用的语法糖
这种设计在RxJS 5.x里是为了兼顾语法简洁和按需导入,但缺点是容易造成不必要的原型污染,而且Tree Shaking的效果不好。到了RxJS 6(对应Angular 6+)就改成了用pipe+可绑定操作符的方式,彻底抛弃了原型扩展。
内容的提问来源于stack exchange,提问作者PaulCo
相关产品推荐
相关产品推荐

