【数组方法reduce】reduce细讲以及模拟重写其他数组扩展方法

学习关键语句:
Array.reduce
Array.prototype.reduce
reduce方法
重写 reduce 方法

1. 写在前面

很多同学 ( 指我自己 ) 在学习其他数组扩展方法时都没那么困难 , 但是到了 reduce 方法时就会显得蠢蠢的 , 所以今天就赶紧将这个方法讲个明白

其实所有的数组扩展方法本质上都是在用循环和遍历 , 所以其实非常简单 , 今天不仅要讲清楚 reduce 的用法 , 还要用 reduce 来模拟其他数组扩展方法

那么赶紧来一起看一看吧

2. 开始

2.1 reduce 的使用方法

reduce 是数组原型对象上的方法 , 所以可以直接从一个数组调用

我们先看 reduce 的使用形式, 如下代码

let initValue = null;
let newArr = arr.reduce(function (pre, cur, index, arr) {
	// 业务代码
}, initValue)

我们看到一共有 4 个形参和 1 个实参 , 分别是
形参 : pre / cur / index / arr
实参 : initValue

我们讲一讲这些都是什么 ( 讲人话 )

  • pre : 第一次接收传入的实参 initValue 值 / 除了第一次以外每次接收上次函数返回的值
  • cur : 当前循环到的数组元素
  • index : 当前循环到的数组的索引
  • arr : 当前循环的数组
  • initValue : 第一次手动给 pre 的值

reduce 方法中会不停的调用第一个参数函数 , 所以 pre 除了第一次的值是手动传入以外 , 接下来每一次的值都是上一次参数函数的返回值

怎么确定 pre 第一次是用的 initValue 的值 ?

let arr = [1];
let initValue = Math.random();
let newArr = arr.reduce(function (pre, cur, index, arr) {
	console.log(pre === initValue); // true
}, initValue)

所以 reduce 并不是用来解决什么具体问题的方法 , 它是一个自由度很高的方法

我们来看两个案例

2.1.1 案例一 : 数组的使用

需求 : 获取到 data 中的人名

// 用 reduce 方法获取到每个对象中的人名
let data = [
  { id: 1, name: '张三', eat: true, age: 24 },
  { id: 2, name: '李四', eat: false, age: 15 },
  { id: 3, name: '王五', eat: false, age: 44 },
  { id: 4, name: '赵六', eat: true, age: 22 },
  { id: 5, name: '林七', eat: true, age: 24 },
]

let initValue = [];
let nameList = data.reduce(function (pre, cur, index, arr) {
	// 第一次的 pre 的值是 initValue 传进来的是一个空的对象
	// 每次将 cur 当前循环到的数组元素的 name 值放进 pre 中
	// 并且将 pre 返回作为这个函数下一次运行时的 pre 的初始值
    pre.push(cur.name);
    return pre;
}, initValue)
console.log(nameList);

在这里插入图片描述

2.1.2 案例二 : 对象的使用

需求 : 将浏览器 cookie 值取出并改为对象形式

// 获取浏览器 cookie
// 这里的 cookie 你可以随便打开一个网页从控制台输入 document.cookie 获取
let cookie = "BIDUPSID=DC121AD5196A1; PSTM=16859; BAIDUID=DC121AD5196A1B69390521:FG=1; BD_UPN=123143; MCITY=-19%3A; sugstore=0; H_PS_PSSID=3964; BAIDUID_BFESS=DC121AD519918590521:FG=1; b-user-id=11b5db-7f7c-ca96-7b82-f9338e5; ZFY=gsXyFw:AG:BaAtZlSnw4Z5YZop6iGeZmA:C; RT=\"z=1&dm=baidu.com&si=158ae890-f910-4a2e-b2ff-7c56&ss=lobi6w&sl=2&tt=1et&bcn=https%3A%2F%2Ffg.baidu.com%2Flog%2Fweirwood%3Ftype%3Dperf&ld=ok&ul=4ztx&d=4zvu\"; BA_HCTOR=0k2k2g8a5212408501l251l1611q; BDORZ=4905EFF3D40215D2BDA1598; Hm_lvt_aec69bb642b076c891cdc49771=16964582,16996550,16921029,19997199; COOKIE_SESSION=4682_2_6_9_3_6_1_0_6_9_1_3_38695_24088_0_5_16995956_16994134_16994129%7C9%23247092_108_16844129%7C9"
// 将一长串字符串分割为以等号相连的数组
let cookieArr = cookie.split(';')
// 对每个数组进行循环操作
let cookieObj = cookieArr.reduce((pre, item) => {
	// 将每项分割为两个元素的数组, 分别是键名和键值
    let arr = item.split('=');
    // 第一次为传入的空对象, 每次给对象写入新属性
    pre[arr[0]] = arr[1];
    // 返回 pre 给下一次的参数函数
    return pre;
}, {})
console.log(cookieObj);

在这里插入图片描述

其实案例说明不了什么 , 就像我上面说的 , reduce 方法太自由了 , 基本上什么都可以实现 , 但是还有一个问题 , 那就是 reduce 方法是 ES5 提出来的 , 没办法让它兼容低版本 , 我们只能重写自己的 reduce 方法

2.2 重写 reduce 方法

想要重写某个数组方法 , 必须先看这个方法的使用方法 , 我们上面已经了解过了

所以我们知道 , 我们的 reduce 方法需要接收两个参数 , 一个是回调函数 , 一个是初始值

Array.prototype.myReduce = function (fn, initValue) {
  var arr = this;
  for (var i = 0; i < arr.length; i++) {
  	// 第一次执行传入的 fn 方法时, pre 的值就由 initValue 直接传入
  	// 每次执行完 fn 方法后, 将返回值赋给 initValue 并进行下一次循环
  	// 每一次新的循环执行 fn 方法都会用到上一次循环返回的 initValue 值
  	// 即每次 pre 的值都是上一次循环返回的值
    initValue = fn(initValue, arr[i], i, arr);
  }
  return initValue;
}

但是我们知道其他的数组扩展方法是可以指定函数中的 this 指向的 , 所以我们稍微修改一下

Array.prototype.myReduce = function (fn, initValue) {
  var arr = this,
  	// 如果用户没有传入指定的 this 指向那就指向 window
    arg2 = arguments[2] || window;
  for (var i = 0; i < arr.length; i++) {
  	// 使用 call 改变 fn 函数的 this 指向, 其他不变
    initValue = fn.call(arg2, initValue, arr[i], i, arr);
  }
  return initValue;
}

2.3 reduce 模拟其他数组方法

reduce 方法是一个自由度很高的方法 , 甚至可以用它完成其他的数组扩展方法 , 我们现在就来试一试

2.3.1 reduce 模拟 forEach 方法

forEach 是最常见的扩展方法之一了 , 用 reduce 模拟显得太鸡肋 , reduce 在其中的作用是循环数组

Array.prototype.myForEach = function (fn) {
  var arr = this,
    arg2 = arguments[1] || window;
  arr.reduce(function (pre, cur, index, arr) {
  	// forEach 中需要的参数分别是元素, 索引, 数组, 一一对上写就好了
    fn.call(arg2, cur, index, arr);
    // 循环遍历不需要 return
  }, null)
}

2.3.2 reduce 模拟 filter 方法

reduce 在 filter 中的作用是循环数组

Array.prototype.myFilter = function (fn) {
  var arr = this,
    arg2 = arguments[1] || window,
    res = [];
  arr.reduce(function (pre, cur, index, arr) {
  	// 参数函数返回值为真的情况下需要将这一元素放入返回数组中
    fn.call(arg2, cur, index, arr) ? res.push(cur) : ''
  }, null)
  return res;
}

2.3.3 reduce 模拟 map 方法

reduce 在 map 中的作用是循环数组

Array.prototype.myMap = function (fn) {
  var arr = this,
    arg2 = arguments[1] || window,
    res = [];
  arr.reduce(function (pre, cur, index, arr) {
  	// 直接将参数函数返回值放入返回数组中
    res.push(fn.call(arg2, cur, index, arr))
  }, null)
  return res;
}

2.3.4 reduce 模拟 every 和 some 方法

reduce 在 every 中的作用是循环数组

Array.prototype.myEvery = function (fn) {
  var arr = this,
    arg2 = arguments[1] || window,
    res = true;
  arr.reduce(function (pre, cur, index, arr) {
  	// 只要有一次参数函数返回了 false 就返回 false
    if (!fn.call(arg2, cur, index, arr)) {
      res = false;
    }
  }, null)
  return res;
}

reduce 在 some 中的作用是循环数组

Array.prototype.mySome = function (fn) {
  var arr = this,
    arg2 = arguments[1] || window,
    res = false;
  arr.reduce(function (pre, cur, index, arr) {
  	// 只要有一次参数函数返回了 true 就返回 true
    if (fn.call(arg2, cur, index, arr)) {
      res = true;
    }
  }, null)
  return res;
}

3. 总结

reduce 作为 ES5 推出的数组扩展方法 , 也是前端必须要学习的东西之一 , 同时我们在重写以及模拟其他方法的过程中 , 我们更能清晰的明白扩展方法其实本质上就是循环遍历然后调用传入的函数而已

4. 结束

reduce 的讲解就告一段落 , 希望你真的有所收获 , 并且在模拟这一部分用 for 循环代替 reduce 方法的话就是其他数组方法的重写了

如果你跟着做遇到了什么问题无法实现 , 请在评论区或者私信告诉我 , 我发动网友给你解答

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/141724.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据结构 顺序表和链表

1.线性表 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列 线性表是一种在实际中广泛使用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列、字符串.. 线性表在逻辑上是线性结构&#xff0c;也就说是连续的一条直线…

2023年【汽车驾驶员(高级)】证考试及汽车驾驶员(高级)实操考试视频

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 汽车驾驶员&#xff08;高级&#xff09;证考试考前必练&#xff01;安全生产模拟考试一点通每个月更新汽车驾驶员&#xff08;高级&#xff09;实操考试视频题目及答案&#xff01;多做几遍&#xff0c;其实通过汽车…

【备忘】在Nginx服务器安装SSL证书

您可以在Nginx或Tengine服务器上安装SSL证书&#xff0c;实现通过HTTPS安全访问Web服务器。本文介绍如何为Nginx或Tengine服务器安装SSL证书。 重要 本文以CentOS 8.0 64位操作系统、Nginx 1.14.2为例介绍。不同版本的操作系统或Web服务器&#xff0c;部署操作可能有所差异&a…

2020年12月 Scratch(一级)真题解析#中国电子学会#全国青少年软件编程等级考试

一、单选题(共25题,每题2分,共50分) 第1题 下面哪个区域是“舞台区”? A:A B:B C:C D:D 答案:B 第2题 下面哪段程序可以随机切换三个背景? A: B: C: D:

私域电商:构建商业新模式的必要性

随着互联网的快速发展&#xff0c;传统的电子商务模式已经无法满足企业对于个性化、精准化服务的需求。在这样的背景下&#xff0c;私域电商应运而生&#xff0c;为企业提供了新的商业机会和增长点。本文将探讨私域电商的必要性及其构建商业新模式的影响。 一、私域电商的概念 …

Python 邮件发送(163为例)

代码 import smtplib import socket from email.mime.text import MIMEText from email.header import Headerdef send_mail():# 设置发件人、收件人、主题、内容from_address 18847097110163.comto_address 963268595qq.comsubject test emailbody hahahhahaha# SMTP邮件…

若依框架下载文件

若依下载的逻辑是指定文件存储的路径&#xff0c;在ruoyi-admin模块下的application.yml中配置路径结尾必须要加/或者\结尾。 他使用的是虚拟路径映射&#xff0c;所以文件名必须是配置路径下真实的文件名。 若依采用的是流的方式&#xff0c;前端必须要用bolb的方式去接收&am…

八大技术架构-演进之路

单机架构 1、简介 应用服务和数据库服务共用一台服务器 2、出现原因 出现在互联网早期&#xff0c;访问量比较小&#xff0c;单机足以满足需求 3、架构工作原理 单机架构通过应用&#xff08;划分了多个模块&#xff09;和数据库在单个服务器上协作完成业务运行&#xff0…

双十一网络电视盒子哪个品牌好?内行分享权威电视盒子排行榜

双十一大促正如火如荼进行中&#xff0c;因为我从事的工作和电视盒子有关&#xff0c;身边的朋友们在选购电视盒子时不知道从何下手就会问我的意见&#xff0c;本期将盘点业内公认的电视盒子排行榜&#xff0c;给双十一想买电视盒子的朋友们做个参考。 排行一&#xff1a;泰捷W…

解决 Django 开发中的环境配置问题:Windows 系统下的实战指南20231113

简介&#xff1a; 在本文中&#xff0c;我想分享一下我最近在 Windows 环境下进行 Django 开发时遇到的一系列环境配置问题&#xff0c;以及我是如何一步步解决这些问题的。我的目标是为那些可能遇到类似困难的 Django 开发者提供一些指导和帮助。 问题描述&#xff1a; 最近…

美颜与性能的平衡:视频直播美颜SDK集成与性能优化指南

目前美颜SDK所遇到的挑战是如何在追求美颜效果的同时保持系统性能的稳定。本文将深入探讨视频直播美颜SDK的集成以及性能优化的关键指南&#xff0c;以帮助开发者找到合适的平衡点。 一、美颜SDK的集成 1.选择适用于直播的美颜SDK 在美颜SDK的众多选择中&#xff0c;要考虑…

文献分享 C-C 模体化学因子受体2的抑制通过恢复免疫细胞格局减轻肝纤维化

C-C 模体化学因子受体2的抑制通过恢复免疫细胞格局减轻肝纤维化 C-C motif chemokine receptor 2 inhibition reduces liver fibrosis by restoring the immune cell landscape 发表于 International Journal of Biological Sciences IF 9.2 摘要 在肝脏中&#xff0c;细胞外…

【从零开始学习Linux】一文带你了解Shell外壳及用户权限(二)

&#x1f6a9;纸上得来终觉浅&#xff0c; 绝知此事要躬行。 &#x1f31f;主页&#xff1a;June-Frost &#x1f680;专栏&#xff1a;Linux入门 &#x1f52d;【从零开始学习Linux】系列均属于Linux入门&#xff0c;主要包含Linux操作系统下的指令、操作、权限以及开发工具&a…

抖音自动发评论之论人工智能AI的应用和发展趋势

人工智能&#xff08;Artificial Intelligence&#xff0c;AI&#xff09;是目前国际上热门的科技话题之一。它是计算机科学中的一个分支&#xff0c;旨在创造能够智能地工作、学习、感知、理解和决策的机器。人工智能的应用范围十分广泛&#xff0c;包括语音识别、自然语言处理…

冰点还原精灵_Deep Freeze Standard v8.60.020.5592中文版

eep Freeze&#xff08;又被成为冰点还原精灵&#xff09;是Faronics公司出品的一款简单易用的系统还原软件&#xff0c;使用能够帮助用户轻松将系统还原到安装该款软件之后状态&#xff0c;避免因为病毒的入侵以及人为的对系统无意或无意的破坏&#xff0c;让你的系统始终完美…

【LeetCode】每日一题 2023_11_12 每日一题 Range 模块(线段树)

文章目录 刷题前唠嗑题目&#xff1a;Range 模块题目描述代码与解题思路 刷题前唠嗑 LeetCode? 启动&#xff01;&#xff01;&#xff01; 嗯&#xff1f;怎么是 hard&#xff0c;好长&#xff0c;可恶&#xff0c;看不懂&#xff0c;怎么办 题目&#xff1a;Range 模块 题…

全国平均风速数据,有图有数据!

全国平均风速数据是一份重要的气象数据&#xff0c;它反映了全国各地的风速情况&#xff0c;对于气象预测、能源开发、环境保护等方面都有重要的意义。 本文将详细介绍全国平均风速数据的来源、统计方法和应用场景&#xff0c;并分析其变化趋势和影响因素。 数据基本信息&#…

【MySQL】MySQL中的锁

全局锁 全局锁是对整个数据库实例加锁&#xff0c;整个库处于只读状态。 flush tables with read lock 适用场景 全局锁适用于做全库逻辑备份&#xff0c;但是整个库处于只读状态&#xff0c;在备份期间&#xff0c;所有的更新操作、DDL将会被阻塞&#xff0c;会对业务产生影…

记一次前后端分离项目跨域导致的set-cookie失效问题解决方案

起因公司项目使用了springsecurity的基础登录进行认证授权&#xff0c;而基础登录使用的是sessioncookie的形式&#xff0c;项目前后端分离&#xff0c;前端调接口的时候就会出现&#xff0c;登陆后点击其他页面&#xff0c;提示未登录跳转登录页的情况&#xff0c;排查了一下问…

图论14-最短路径-Dijkstra算法+Bellman-Ford算法+Floyed算法

文章目录 0 代码仓库1 Dijkstra算法2 Dijkstra算法的实现2.1 设置距离数组2.2 找到当前路径的最小值 curdis&#xff0c;及对应的该顶点cur2.3 更新权重2.4 其他接口2.4.1 判断某个顶点的连通性2.4.2 求源点s到某个顶点的最短路径 3使用优先队列优化-Dijkstra算法3.1 设计内部类…