在开发中,不同输入输出所存储和使用数据总会存在差异,或是数据类型、字段经常出现偏差。
当前后端分离开发时,服务端返回的数据与前端渲染时所定义的数据,即使是相同的业务逻辑,也会存在差异。又或者使用多个开源组件时,相互间需要传递的数据类型定义也会有差异。
但是,在相同的业务场景,这种数据的差异又仅仅是表象的差异,比如:字段键名不同,值的数据类型不同。
通过开发经验归纳,有下面三种差异:
key 名称不一致
value 类型不一致
数据结构不一致:输入是 {a,b,c},输出是 {a,b} 或 {a,b,c,d}
当然,实际开发中还存在着更复杂的差异,那样的情状建议特例化处理。
而造成这种情况的原因通常是开发协作时沟通不够详尽,或是开源组件缺乏统一的规范。为了简化处理这种情况的流程,更合适的实践方案是在前端通过数据转换函数进行归一化处理。
针对上述数据差异,我开源了数据转换库 d-pipe。
使用
import Pipe from 'd-pipe';
const data = { a: 'a', b: 'b' };const pipe = new Pipe(data);pipe .add('c', () => 'c') .delete(['b']) .editValue('a', () => 'aa');pipe.data; // { a: 'aa', c: 'c' }
复制代码
在 Pipe 实例化导入数据 data,再通过可链式调用的转换方法 add,delete 等对数据进行转换。
Tips:传入的数据必须是非空对象和非空数组,{} 和 [] 都是不允许的数据。开发者必须在业务中明确判断数据是非空的,才能传递给 Pipe。
否则 Pipe 将抛出一个类型错误: The dataSet must be an Object or Array,and cannot be an empty object or empty array.
关于所有转换方法的介绍和使用请查看 README。
特征
immutable:内部使用 cloneDeep 函数,对传入的数据进行深拷贝,所有修改不影响原始数据
constructor(data: any) { this.originalData = deepClone(data); this.result = deepClone(data); }
复制代码
方法调用顺序无关:使用链式调用方法时无需关心代码书写顺序,内部始终使用固定的执行顺序(具体顺序查看 README)。
// 测试用例 test('valueDelivery', () => { const data = { a: 'a', b: 'b' }; const pipe = new Pipe(data); pipe .add('c', () => 'c') .delete(['b']) .editValue('a', () => 'aa'); expect(pipe.data).toEqual({ a: 'aa', c: 'c' }); // pass // 顺序无关 pipe .editValue('a', () => 'aa') .add('c', () => 'c') .delete(['b']); expect(pipe.data).toEqual({ a: 'aa', c: 'c' }); // pass });
复制代码
归纳操作:Pipe 内部会收集所有调用方法,以便于对数组数据只使用一次遍历完成数据操作
// 源码:src/core/pipe.ts private convert() { // NOTE: 判断是否是数组 if (Array.isArray(this.originalData)) { this.result = this.originalData.map((item, index) => { // NOTE: 当是最后一条数据时,使用 forEachOnce ,来清除记录,从而不重复计算 const type = index === (this.originalData as T[]).length - 1 ? 'forEachOnce' : 'forEachAlways'; return this.convertItem(item, type); }); } else { this.result = this.convertItem(this.originalData, 'forEachOnce'); } if (this.noExitKeys.size > 0) { console.warn( `[warn]:Fields of ${[...this.noExitKeys].join(',')} do not exist.`, ); } }
复制代码
链式调用:使用链式调用方法,使代码更有组织性,阅读性更佳,更便于维护。
类型描述:d-pipe 完全使用 typescript 编写,具有完备的类型描述。
示例
const data = { price: 100, discount: undefined }; const pipe = new Pipe(data); pipe.clean([undefined, null, '']); console.log(pipe.data); // {price:100}
复制代码
const data = { name: 'Jane', vip: '100', gender: 'male' }; const pipe = new Pipe(data); pipe.pick(['name', 'gender']); console.log(pipe.data); // {name:"Jane",gender:"male"}
复制代码
评论