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

实现Underscore.js的reduce函数:accumulator未定义时如何跳过首次迭代

精简Underscore.js reduce实现的方案

问题分析

你的代码核心逻辑是正确的,但数组和对象的处理模块存在大量重复代码。两者仅在元素获取方式(数组用索引、对象用键)和初始值来源上有差异,其余逻辑完全一致,可通过抽离公共逻辑消除冗余。

优化后的代码

_.reduce = function (collection, iteratee, accumulator, context) {
  // 统一生成可迭代的键列表:数组用索引序列,对象用Object.keys
  const keys = Array.isArray(collection) 
    ? Array.from({ length: collection.length }, (_, i) => i) 
    : Object.keys(collection);
  
  let returnVal = accumulator;
  let startIndex = 0;

  // 处理accumulator未定义的场景:用第一个元素初始化,循环从第二个元素开始
  if (returnVal === undefined) {
    returnVal = collection[keys[0]];
    startIndex = 1;
  }

  // 统一执行循环逻辑,无需区分数组/对象
  for (let i = startIndex; i < keys.length; i++) {
    const key = keys[i];
    returnVal = iteratee.call(
      context,
      returnVal,
      collection[key],
      key,
      collection
    );
  }

  console.log(returnVal);
  return returnVal;
};

优化说明

  1. 统一键列表:将数组索引转换为和对象键结构一致的列表,让数组和对象的循环逻辑完全复用,避免分支冗余。
  2. 提前确定循环起点:在循环前就完成accumulator的判断,直接设置初始值和起始索引,解决了你之前用continue无效的问题。
  3. 消除重复代码块:原代码中数组和对象的循环、iteratee调用模块完全重复,现在通过统一逻辑实现了代码精简,可读性和维护性大幅提升。

额外改进建议

  • 用let/const替代var:避免变量提升带来的潜在问题,提升代码安全性。
  • 处理空集合边界:当集合为空且未传入accumulator时,应抛出错误或返回undefined,对齐Underscore原生行为。
  • 移除调试输出:生产代码中无需保留console.log。

内容的提问来源于stack exchange,提问作者Niels Koop

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 23:15:18