使用Ramda实现跨数组条件更新元素 规避no-param-reassign报错
Ramda函数式实现数组属性追加方案
前置定义
题目中给出的两个基础数组定义如下:
const array_one = [ {id:'a',city:'Sydney',offer:'HAS'}, {id:'b',city:'Sydney',offer:'AHR'}, {id:'c',city:'Perth',offer:'AHR'}, ]; const array_two = [ {id:'a',html:''}, {id:'b',html:''}, {id:'c',html:''}, {id:'d',html:''}, {id:'e',html:''}, ];
需求说明
为array_two每个元素新增布尔属性isEligible,规则如下:
- 若
array_one中存在同id元素,且该元素city === 'Sydney'且offer === 'AHR',则属性值为true - 其余所有场景(包括
array_one无对应id的元素)属性值默认为false
预期输出结果:
const array_two = [ {id:'a',html:'', isEligible: false}, {id:'b',html:'', isEligible: true}, {id:'c',html:'', isEligible: false}, {id:'d',html:'', isEligible: false}, {id:'e',html:'', isEligible: false}, ];
原有实现的问题
最初的实现存在以下问题,触发ESLint报错且逻辑不生效:
- 直接在
forEach遍历中修改入参对象,触发no-param-reassign规则 - Ramda API调用语法错误:
R.allPass是函数需要用()调用传入谓词数组,原代码误用[]下标访问;R.propEq、R.equals参数顺序不符合Ramda规范 - 拼写错误:属性名
isEligible错写为isElibible,目标offer值AHR错写为AMR - 无空值兼容:当
array_one中找不到对应id时,arrayOneItem为undefined,直接访问city/offer属性会抛出JS错误
纯Ramda函数式实现
全程不修改原数组/原对象,无参数重赋值,完全符合函数式不可变规范:
// 提前将array_one转为id为key的索引对象,避免重复遍历查找,优化性能 const arrayOneMap = R.indexBy(R.prop('id'), array_one); // 封装资格判断逻辑 const getEligibleStatus = R.pipe( R.prop('id'), // 从索引中取对应条目,不存在则返回null id => R.propOr(null, id, arrayOneMap), R.ifElse( // 无对应条目直接返回false R.isNil, R.F, // 存在条目则同时校验city和offer两个条件 R.allPass([ R.propEq('city', 'Sydney'), R.propEq('offer', 'AHR') ]) ) ); // 遍历生成新数组,不修改原array_two const updatedArrayTwo = R.map( item => R.assoc('isEligible', getEligibleStatus(item), item), array_two );
实现说明
- 规避lint报错:全程通过
R.map返回全新数组、R.assoc返回追加属性后的全新对象,没有任何对入参的重赋值操作,完全符合no-param-reassign规则要求 - 空值安全:通过
R.propOr兜底不存在的id场景,不会出现访问undefined属性的报错 - 性能更优:
R.indexBy预处理后仅需两次线性遍历即可完成计算,比嵌套find的实现时间复杂度更低 - 逻辑可复用:资格判断逻辑被封装为独立函数,可直接复用到其他场景
内容的提问来源于stack exchange,提问作者Nadhas
相关产品推荐
相关产品推荐

