You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

函数式实现:查找数组指定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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 01:45:44