函数式实现:查找数组指定child元素前最近的parent项
问题描述
我有一个结构如下的对象数组:
const items: item[] = [ {id: 1, type: 'parent'}, {id: 2, type: 'parent'}, {id: 3, type: 'child'}, {id: 4, type: 'child'}, ]
需要实现一个函数:传入type为child的元素时,返回该元素之前位置上第一个type为parent的元素。
要求符合函数式编程的immutable(不可变)规范,目前已有可运行的命令式伪代码:
function getParentItem(item: item) let startIndex = items.indexOf(item) let item = null while(!item){ if(items[startIndex].type == "parent"){ item = items[startIndex] } startIndex-- } return item } getParentItem({id: 4, type:'child'}) // 预期返回 {id: 2, type: 'parent'}
求优雅的immutable函数式实现方案。
实现方案
函数式实现核心要满足三个要求:纯函数无副作用、不修改输入数据、不使用可变状态变量。
简洁版(ES2023+ 原生支持)
用原生slice做数组切片(返回新数组,不修改原数组),搭配findLast从切片尾部倒序查找第一个匹配的parent元素,逻辑最直观:
const getParentItem = (allItems: item[], target: item): item | undefined => { const targetIdx = allItems.indexOf(target) if (targetIdx === -1) return undefined // 截取目标元素之前的所有元素,不改动原数组 return allItems.slice(0, targetIdx).findLast(item => item.type === 'parent') } // 调用示例 getParentItem(items, {id: 4, type: 'child'}) // 返回 {id: 2, type: 'parent'}
注意:这里把数据源数组作为参数传入函数,而不是直接闭包引用外部的
items变量,避免依赖外部可变状态,保证函数是纯函数——相同输入永远得到相同输出。
兼容版(无ES2023依赖)
如果运行环境不支持findLast,可以用reduceRight实现倒序遍历,全程无可变变量:
const getParentItem = (allItems: item[], target: item): item | undefined => { const targetIdx = allItems.indexOf(target) if (targetIdx === -1) return undefined return allItems .slice(0, targetIdx) .reduceRight( (matched, current) => matched ?? (current.type === 'parent' ? current : undefined), undefined ) }
两种实现都完全符合immutable要求:
- 没有修改原数组、输入参数的任何操作
- 没有使用
let声明可变变量,所有值都是不可变的常量 - 无副作用,输出完全由输入决定,不受外部状态影响
- 声明式逻辑,不需要手动维护循环计数器、循环终止条件等命令式控制流
内容的提问来源于stack exchange,提问作者Josh
相关产品推荐
相关产品推荐

