iis服务器助手广告广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >reduce探索lodash.reduce实现原理解析
  • 624
分享到

reduce探索lodash.reduce实现原理解析

reducelodash.reducereduce原理 2023-02-27 08:02:08 624人浏览 独家记忆
摘要

目录前言基本实现lodash 中的 reduce 实现有何不同?总结前言 前一篇 你真的了解Array.reduce吗? 讲解了 reduce 基础使用方法和场景的运用场景。本篇来分

前言

前一篇 你真的了解Array.reduce吗? 讲解了 reduce 基础使用方法和场景的运用场景。本篇来分析一下 reduce 函数本身的实现原理。

实现 reduce 其实挺简单的,因为它本身的运行原理也不难,就是把数组进行遍历,然后组成合适的参数传递给回调函数,只要思路对了,去尝试几次,那么就理解了 reduce 。

最具有代表性的工具库当然是 lodash,因此本篇文章的主要内容会讲解 reduce 的基本实现,以及lodash 中是怎么来实现的,做了什么处理。

基本实现

实现思路:

  • 判断是否有初始值,因为有初始值和没有初始值对回调函数(reducer)执行的次数是有影响的。
  • 遍历数组
  • 组合参数传递给 reducer 进行执行
  • 获取到第三步返回值的时候,要把返回值存储起来,在下一次便利的时候作为reducer第一个参数来替换初始值。
  • 返回最终计算的value值
function reduce(array, reducer, initialValue = null) {
    let value = initialValue === null ? array[0] : initialValue; // 思路1
    let startIndex = initialValue === null ? 1 : 0; // 思路1
    for(let i = startIndex; i < array.length; i++) { // 思路 2
        const item = array[i]
        const res = reducer(value, item, i) // 思路3
        value = res; // 思路4
    }
    return value; // 思路5
}
复制代码

测试一下:

console.log(reduce([1,2,3], (a, b) => (a + b), 0)) // 6
console.log(reduce([1,2,3], (a, b) => (a + b))) // 6
复制代码

看起来是不是挺简单的,代码其实还可以更简洁一点:

function reduce(array, reducer, value = null) {
    value = value === null ? array[0] : value;
    for(let i = null ? 1 : 0; i < array.length; i++) {
        value = reducer(value, array[i], i);
    }
    return value;
}
复制代码

lodash 中的 reduce 实现有何不同?

lodash中 的 reduce 不仅可以对数组生效,也可以对普通 object 、类数组对象生效。

不过也针对数组其实单独实现了一个 arrayReduce 函数,不过没有对外。

来看一下 reducearrayReduce 源码

function reduce(collection, iteratee, accumulator) {
  const func = Array.isArray(collection) ? arrayReduce : baseReduce
  const initAccum = arguments.length < 3
  return func(collection, iteratee, accumulator, initAccum, baseEach)
}

function arrayReduce(array, iteratee, accumulator, initAccum) {
  let index = -1
  const length = array == null ? 0 : array.length

  if (initAccum && length) {
    accumulator = array[++index]
  }
  while (++index < length) {
    accumulator = iteratee(accumulator, array[index], index, array)
  }
  return accumulator
}
复制代码

看得懂吗?不理解的话看下面一份代码,我把非数组类型的代码去掉,再调一下变量命名和新增注释:

function reduce(array, reducer, value) {
  const noInitialValue = arguments.length < 3 // 用参数的数量来判断是否有初始值
  
  let index = -1 // 遍历索引 - 1,因为下面 while 循环前先加了 1
  const length = array == null ? 0 : array.length // 判断数组是否存在和缓存数组长度
  // 这个if 语句中做了我上面思路1中初始值的问题和遍历次数的问题
  if (noInitialValue && length) { // && length 判断了数组是否为空
    value = array[++index] // 没有有初始值,则取数组中第一为,注意 index 变成了0,下面 while 循环前会先加 1,因此循环次数会少一次。
  }
  while (++index < length) {
    value = reducer(value, array[index], index, array)
  }
  return value
}
复制代码

可以看出其实大部分逻辑还是和前面的简单实现差不多,不过考虑更全一些,有值得借鉴的地方:

  • 参数判断逻辑更有力,不管外界传递了第三个参数是啥,都说明有初始值
  • 考虑了数组不存在或者为空的情况

下面我们再看一下,去除数组相关的代码来看看针对其他对象类型怎么处理的。

function reduce(collection, iteratee, accumulator) {
  const func = baseReduce;
  const initAccum = arguments.length < 3
  return func(collection, iteratee, accumulator, initAccum, baseEach)
}
复制代码

其他类型的都会教给 baseReduce 函数去处理。

// baseReduce
function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) {
  // 使用外部传递进来的遍历方法进行遍历对象,然后传递了一个 callback 给 eachFunc
  eachFunc(collection, (value, index, collection) => {
    // 初始值设置,
    accumulator = initAccum
      ? (initAccum = false, value)
      : iteratee(accumulator, value, index, collection)
  })
  return accumulator
}
复制代码

使用外部传递进来的遍历方法进行遍历对象,然后传递了一个 callback 给 eachFunc,来执行 iteratee (也就是前面说的reducer),callback 内部的代码就和前面 for 循环或者 while 循环的代码类似的,就是组合参数传递给 reducer 进行执行,不过直接看可能有点不好理解中,了解了原理再来看应该可以理解,注意事项:

  • initAccum 为 false 时,说明有初始值,直接执行 iteratee。
  • initAccum 为 true,说明没有初始值,需要添加初始值,因此第一次循环就是赋值给初始值,然后把 initAccum 设置为false,没有进行执行 iteratee,比没有初始值少一次执行,符合逻辑。

eachFunc 用的是 reduce 中传递进来的 baseEach,内部主要就是对对象属性进行遍历的操作,然后把属性值和索引以及对象本身传递给 callback,稍微需要注意的就是可能遇到类数组的对象,为了保证顺序,使用类数组放入索引进行遍历,而其他对象并不能保证属性的传递顺序,可以再看一下baseEach实现的代码:

function baseEach(collection, iteratee) {
  if (collection == null) {
    return collection
  }
  // 不是类数组则使用 baseForOwn 处理
  if (!isArrayLike(collection)) {
    return baseForOwn(collection, iteratee)
  }
  const length = collection.length
  const iterable = Object(collection) // 使用arguments测试了一下,好像没啥作用
  let index = -1

  // 遍历类数组
  while (++index < length) {
    if (iteratee(iterable[index], index, iterable) === false) {
      break
    }
  }
  return collection
}
复制代码

不是 isArrayLike 的对象遍历与本篇文章的内容没有啥关系了,因此就不深入了。

总结

最近一直在学函数式编程,而 reduce 可以很好的契合函数式编程中的函数组合思想,因此最近几篇文章中都涉及到它,就想一次性把它给写透彻,希望对读者又一些帮助。

以上就是reduce探索lodash.reduce实现原理解析的详细内容,更多关于reduce lodash.reduce实现的资料请关注编程网其它相关文章!

--结束END--

本文标题: reduce探索lodash.reduce实现原理解析

本文链接: https://www.lsjlt.com/news/197589.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • reduce探索lodash.reduce实现原理解析
    目录前言基本实现lodash 中的 reduce 实现有何不同?总结前言 前一篇 你真的了解Array.reduce吗? 讲解了 reduce 基础使用方法和场景的运用场景。本篇来分...
    99+
    2023-02-27
    reduce lodash.reduce reduce原理
  • reduce lodash.reduce实现原理是什么
    本篇内容主要讲解“reduce lodash.reduce实现原理是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“reduce lodash.reduce实现原理是什么”吧!基本实现实现思路...
    99+
    2023-07-05
  • Golang多进程原理解析与实践探索
    标题:Golang多进程原理解析与实践探索 在当今工程领域中,多进程技术在系统性能优化和任务处理效率方面扮演着重要角色。Go语言作为一种并发性能优秀的编程语言,也提供了强大的多进程支持...
    99+
    2024-03-01
    golang 多进程 探索 go语言
  • 探索数据库的实现原理
    本篇内容介绍了“探索数据库的实现原理”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!归并连接的思想与归并排序...
    99+
    2024-04-02
  • 解析探秘fescar分布式事务实现原理
    目录前言项目说明fescar的TXC模型项目结构解析通过【examples】模块的实例看下效果第一步、第二步、第三步、fescar事务过程分析首先分析配置文件【TM】模块启动全局事务...
    99+
    2024-04-02
  • Mysql索引的实现原理分析
    本篇文章为大家展示了Mysql索引的实现原理分析,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。  一:Mysql原理与慢查询  MySQL凭借着出色的性能、低廉的成...
    99+
    2024-04-02
  • iOS底层探索之自动释放池原理解析
    目录1、概述2、底层探索2.1、打印自动释放池结构2.2、objc_autoreleasePoolPush2.2.1、AutoreleasePoolPage2.2.2、Autorel...
    99+
    2024-04-02
  • 探索Golang中除法运算符的实现原理
    探索Golang中除法运算符的实现原理 在Golang中,除法运算符/用于执行除法计算。但是,要了解除法运算符的实现原理,我们需要深入了解Golang中的底层实现机制。Golang是一...
    99+
    2024-03-13
    原理 golang 除法
  • 深入探索:Go WaitGroup的原理和内部实现
    WaitGroup是Go语言中的一个并发同步原语,用于等待一组goroutine的完成。它提供了三个主要的方法:Add、Done和W...
    99+
    2023-10-08
    Golang
  • GolangWaitGroup实现原理解析
    原理解析 type WaitGroup struct { noCopy noCopy // 64-bit value: high 32 bits are counter,...
    99+
    2023-02-03
    Go WaitGroup Go WaitGroup实现原理
  • Python 探针实现原理
    本文将简单讲述一下 Python 探针的实现原理。 同时为了验证这个原理,我们也会一起来实现一个简单的统计指定函数执行时间的探针程序。 探针的实现主要涉及以下几个知识点: sys.meta_path sitecustomize.py ...
    99+
    2023-01-31
    探针 原理 Python
  • Mysql索引实现原理的示例分析
    这篇文章主要为大家展示了“Mysql索引实现原理的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Mysql索引实现原理的示例分析”这篇文章吧。MySQL...
    99+
    2024-04-02
  • 剖析 ASP 控件状态管理:探索其原理和最佳实践
    控件状态管理机制 ViewState:一种服务器端机制,将控件状态作为隐藏字段存储在 HTML 中。 ControlState:一种客户端机制,将控件状态作为 JSON 数据存储在客户端。 Session State:一种服务...
    99+
    2024-04-02
  • Vue3 KeepAlive实现原理解析
    目录思路代码解析setuprenderonActivated 和 onDeactived调用思路 首先我们知道 KeepAlive 是一个内置组件,那封装一个组件对于大家来说应该不会...
    99+
    2024-04-02
  • PHP 自动加载的深入探索:从原理到实现
    PHP 自动加载是一种机制,它允许在需要时自动加载类,而无需明确地使用 include 或 require 语句。它对于管理大型代码库和防止由于缺少类定义而导致的错误非常有用。 原理 PHP 自动加载的工作原理是基于一个称为 "自动加载...
    99+
    2024-03-01
    PHP、自动加载、composer、spl_autoload_register、__autoload
  • Golangmap实践及实现原理解析
    目录Map实践以及实现原理使用实例内存模型创建maphash函数key定位和碰撞解决扩容元素访问删除迭代Map实践以及实现原理 使用实例内存模型创建maphash函数key定位和碰撞...
    99+
    2024-04-02
  • gosyncOnce实现原理示例解析
    目录正文Once 的实现使用示例Once 的一些工作机制Once 详解hotpathatomic.LoadUint32atomic.StoreUint32Mutex总结正文 在很多...
    99+
    2023-01-03
    go sync Once实现原理 go sync.Once
  • Vue响应式原理模拟实现原理探究
    目录前置知识数据驱动数据响应式的核心原理Vue 2.xVue 3.x发布订阅和观察者模式发布/订阅模式观察者模式Vue响应式原理模拟实现VueObserver对data中的属性进行监...
    99+
    2024-04-02
  • Java CompletableFuture实现原理分析详解
    目录简介CompletableFuture类结构CompletableFuture回调原理CompletableFuture异步原理总结简介 前面的一篇文章你知道Java8并发新特性...
    99+
    2024-04-02
  • java LockSupport实现原理示例解析
    目录引言LockSupport常见函数LockSupport.parkLockSupport.unpark引言 前文中了解到AQS借助LockSupport.park和LockSup...
    99+
    2023-01-09
    java LockSupport原理 java LockSupport
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作