sunnyxujian's blog sunnyxujian's blog
首页
  • JavaScript
  • CSS
  • HTML和浏览器
  • Vue
  • Vue3
  • React
  • 基础知识
  • webpack
  • rollup
  • vite
  • 其他
  • Nodejs
  • 网络
  • TypeScript
  • 架构设计
  • 性能优化
  • 数据结构和算法
  • JavaScript教程 笔记
  • ES6 教程 笔记
  • TypeScript 从零实现 axios
  • Git学习 笔记
  • 渲染器原理
  • TypeScript 笔记
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • 网站
  • 资源
  • Vue资源
  • 友情链接
  • 分类
  • 标签
  • 归档
  • 友链
  • 关于
GitHub (opens new window)

xujian

劝君惜取少年时。
首页
  • JavaScript
  • CSS
  • HTML和浏览器
  • Vue
  • Vue3
  • React
  • 基础知识
  • webpack
  • rollup
  • vite
  • 其他
  • Nodejs
  • 网络
  • TypeScript
  • 架构设计
  • 性能优化
  • 数据结构和算法
  • JavaScript教程 笔记
  • ES6 教程 笔记
  • TypeScript 从零实现 axios
  • Git学习 笔记
  • 渲染器原理
  • TypeScript 笔记
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • 网站
  • 资源
  • Vue资源
  • 友情链接
  • 分类
  • 标签
  • 归档
  • 友链
  • 关于
GitHub (opens new window)
  • JavaScript

    • JavaScript深入之从原型到原型链
    • 继承的多种方式和优缺点
    • 作用域链及闭包
    • JavaScript深入之闭包
    • 变量提升
    • this指向
    • instanceof 和 typeof 的实现原理
    • 深入bind的模拟实现
    • apply 和 call
    • 😍Vue3和React都在用的函数式编程,学起来~
    • 手写Promise内部原理
    • 高阶函数魅力
    • 那些神仙API之数组reduce方法
      • 防抖与节流函数
      • JS获取和修改url参数
      • 比typeof运算符更准确的类型判断
      • new命令原理
    • CSS

    • HTML和浏览器

    • 前端基础
    • JavaScript
    xujian
    2020-10-19

    那些神仙API之数组reduce方法

    reduce方法可以搞定的东西,for循环,或者forEach方法有时候也可以搞定,那为啥要用reduce?这个问题,之前我也想过,要说原因还真找不到,唯一能找到的是:通往成功的道路有很多,但是总有一条路是最捷径的,亦或许reduce逼格更高...

    shu.sir.png

    reduce接收2个参数,第一个参数是累加处理函数(必传),第二个是初始值(可选),如果第二个参数没有传,就默认把数组的第一项做初始值在累加函数里处理。reduce会用累加函数依次处理数组的每一项,累加函数接收4个参数:始值(上一次回调的返回值),当前元素值,当前索引,原数组。


    语法: Array.reduce(callback,[initialValue])

    callback函数四个参数:

    • accumulator:上一次调用回调返回的值,或者是提供的初始值(initialValue)
    • currentValue:数组中当前被处理的元素
    • index:当前元素在数组中的索引
    • array:源数组

    参数解析:

    // 求和&参数打印
    var const = [1, 2, 3, 4];
    var const = arr.reduce(function(prev, cur, index, arr) {
        console.log(prev, cur, index);
        return prev + cur;
    })
    console.log(sum);
    
    // 打印结果
    // 1 2 1
    // 3 3 2
    // 6 4 3
    // 10
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    # 手写reduce实现

    清楚了reduce的行为后,手写一个reduce其实并不难

    Array.prototype.myReduce = function(accumulator,initialValue){ // reduce 接收2个参数:累加函数和初始值
      if(typeof accumulator !== 'function') return // 累加器不是函数退出
      for(let i = 0;i<this.length;i++){ // 通过arr.myReduce来调用的,所以this是当前数组
       if(initialValue === undefined) { 
         initialValue = this[i] // 如果没传initialValue值,就把第一项作为初始值
         i++ // 当前的索引要向前移一位,此时被处理的元素是第二个
         initialValue = accumulator(initialValue, this[i], i, this) // 执行累加器函数并赋值
       } else {
    		 initialValue = accumulator(initialValue, this[i], i, this) // 后续直接执行
       }
      }
      return initialValue
    }
    
    // case
    const arr = [1, 2, 3, 4];
    const sum = arr.myReduce(function(prev, cur, index, arr) {
        console.log(prev, cur, index);
        return prev + cur;
    })
    console.log(sum);
    // 打印结果:
    // 1 2 1
    // 3 3 2
    // 6 4 3
    // 10
    
    // 更简洁的实现
    Array.prototype.myReduce = (accumulator, initialValue)=> {
      if (typeof accumulator !== 'function') return
      for (let i = 0; i < this.length; i++) {
        initialValue = initialValue === undefined ? accumulator(this[i], this[++i], i, this) : accumulator(initialValue, this[i], i, this)
      }
      return initialValue
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35

    reduce的返回值可以是任意类型的,几乎可以用它代替所有的数组方法,可玩性极强,下面演示几个例子展示一下它的能力。

    # compose函数

    很多开源框架例如express,redux用都用到了compose函数,它用于将多个函数组成一个函数,什么意思呢?举个例子: case: fn1的返回值是fn2的入参,fn2的返回值是fn3的入参...... 这样就会形成套娃一样的一层套一层,很不美观,可能听着有点懵,代码演示一下。

    function sum(a,b) {
      return a + b
    }
    
    function length(str) {
      return str.length
    }
    
    function addPrefix(str) {
        return '$' + str;
    }
    
    let result = addPrefix(len(sum('a','b'))); // 多层嵌套,逻辑不清晰
    console.log(result) // $2
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15

    compose就是要解决这个问题的,用于返回一个新函数,直接执行这个新函数就可以了。

    // 上面的函数执行顺序是有要求的,要用里往外执行,所以用reduceRight会比较方便点,
    // reduceRight和reduce一样的逻辑,只是执行方向相反。最后要注意的是,它的返回值是一个函数。
    function compose(...fns) {
      return function (...args) {
        const lastFn = fns.pop() // 取出最后一个函数在下面执行作为值
        return fns.reduceRight(function (prev, current) {
          return current(prev) // 执行当前函数它的参数是后一个的返回值,如:执行length(str) str是sum的返回值
        }, lastFn(...args))
      }
    }
    
    let finalFn = compose(addPrefix, len, sum)
    const result = finalFn('a', 'b');
    console.log(result) // $2
    
    // 更简洁的实现
    const compose = (...fns) => (...args) => {
      let lastFn = fns.pop();
      return fns.reduceRight((prev, current) => current(prev), lastFn(...args))
    }
    
    // 其实用reduce也可以实现就是可能难理解一点,实际上redux里面的compose就是这样实现的
    const compose = (...fns) => fns.reduce((a, b) => (...args) => a(b(...args)))
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24

    redux compose https://github.com/reduxjs/redux/blob/master/src/compose.ts#L46 (opens new window)

    编辑 (opens new window)
    #reduce
    上次更新: 2022/05/23, 15:08:15
    高阶函数魅力
    防抖与节流函数

    ← 高阶函数魅力 防抖与节流函数→

    最近更新
    01
    😍Vue3和React都在用的函数式编程,学起来~
    02-03
    02
    链表
    11-24
    03
    基础类型
    11-18
    更多文章>
    Theme by Vdoing | Copyright © 2020-2023 xujian | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式