deep-rxjs之ObservableArray
可观察数组继承自普通数组。javascript语言特性,Array的任何方法都可以通过派生类ObservableArray访问。其中的读取方法,比如arr.length,可以随意使用。初学者不要使用Array自带的修改方法,比如push,pop。而要使用ObservableArray包装的可发射通知的三个方法。
observable array名称来自knockout中。
Observable Array位于deep-rxjs库中。请用npm安装。
deep-rxjs是开源的前端库。位于github上,见xp44mm/deep-rxjs仓库。
构造器
import { ObservableArray } from './ObservableArray'
let arr = new ObservableArray()
可观察数组初始化,不能有参数,此时是空数组。这是因为为数组添加元素将会有其他关联的数据随之变化。这个关联需要在添加元素之前进行配置。请继续阅读。
insertBefore与insertBefore$
insertBefore插入新元素到数组指定索引位置。后面的元素依次向后移动一个索引。其语法
array.insertBefore(e, i=this.length)
e是被插入的新元素,i是插入的位置,缺省是数组末尾。每次执行insertBefore时,会通过insertBefore$发射Observable通知。通知的数据即是insertBefore的输入参数数组。
test('test insertBefore', done => {
let states = []
let arr = new ObservableArray()
arr.insertBefore$.subscribe(([item, index]) => {
states.push(['insertBefore', item, index])
})
arr.insertBefore(4)
arr.insertBefore(3)
arr.insertBefore(2, 0)
expect(states).toEqual([
['insertBefore', 4, 0],
['insertBefore', 3, 1],
['insertBefore', 2, 0],
])
expect([...arr]).toEqual([2, 4, 3])
expect(arr.length).toEqual(3)
done()
})
我们在订阅中执行向外部数组states附加记录。我们检测所作的副作用,并且可观察数组的当前状态。
removeChild与removeChild$
removeChild删除数组中指定索引位置的元素,后面的元素依次向前补位。其语法
removeChild(index = this.length - 1)
索引是其唯一输入参数。其可以省略,默认是数组的最后的索引。每次执行removeChild时,会通过removeChild$发射observable通知。通知的数据即是removeChild的输入参数。
test('test removeChild', done => {
let states = []
let arr = new ObservableArray()
arr.removeChild$.subscribe(index => {
states.push(['removeChild', index])
})
arr.insertBefore(4)
arr.insertBefore(3)
expect([...arr]).toEqual([4, 3])
expect(arr.length).toEqual(2)
arr.removeChild()
arr.removeChild(0)
expect(arr.length).toEqual(0)
expect(states).toEqual([
['removeChild', 1],
['removeChild', 0],
])
expect([...arr]).toEqual([])
done()
})
replaceChild与replaceChild$
replaceChild替换指定索引的元素。其语法
array.replaceChild(e,i)
e是用户提供的新元素,i是旧元素的索引位置。用新元素e,替换数组i位置的现有元素。并没有其他变化。每次执行replaceChild时,会通过replaceChild$发射observable通知。通知的数据即是replaceChild的输入参数数组。
test('test replaceChild', done => {
let states = []
let arr = new ObservableArray()
arr.replaceChild$.subscribe(([item, index]) => {
states.push(['replaceChild', item, index])
})
arr.insertBefore(4)
arr.insertBefore(3)
arr.insertBefore(2, 0)
expect([...arr]).toEqual([2, 4, 3])
arr.replaceChild('4', 1)
expect(states).toEqual([
['replaceChild', '4', 1],
])
expect([...arr]).toEqual([2, '4', 3])
done()
})
action
以上三个方法的通知,insertBefore$,removeChild$,replaceChild三个Observable可观察数组成员。实际上是action发射的,其类型为Subject。发射通知数据是一个数组,元素依次为动作名称,动作参数。
test('test action', done => {
let states = []
let arr = new ObservableArray()
arr.action.subscribe(a => { states.push(a) })
arr.insertBefore('a')
arr.replaceChild('b', 0)
arr.removeChild()
expect(states).toEqual([
['insertBefore', 'a', 0],
['replaceChild', 'b', 0],
['removeChild', 0],
])
expect([...arr]).toEqual([])
done()
})
已知问题
当使用许多从array继承来的方法时,这些方法会自动使用派生类的构造函数,有时可能会引发错误,解决方案是克隆可观察数组为内建数组
observableArray.map(x=>x)
map会在映射后调用ObservableArray构造函数构造一个ObservableArray,这违反ObservableArray构造函数参数表必须为空的限制条件。解决方案是读取元素,克隆到另一个数组:
[...observableArray].map(x=>x)