数组中的各种迭代API方法手写

news2024/11/29 22:41:10

js的数组上有很多实用的方法,不论是在遍历数组上,还是在操作数组内元素上,它有许多不同的遍历数组的方法,同时它还有着可以直接操作数组中间元素的方法。

接下来,我来带大家手写数组里的 遍历方法

Array.forEach()

首先, Array.forEach() 接收一个回调作为参数;

同时,在它的回调则接收三个参数,分别代表着(数组项,下标,整个数组本身);

最后,forEach 会把数组进行遍历调用这个传进去的回调函数。

例如:

const singer = [{ name: '周杰伦', num: 20 },{ name: '许嵩', num: 25 },{ name: '林俊杰', num: 19 },{ name: '蔡徐坤', num: 10 },{ name: '鹿晗', num: 0 },
];

singer.forEach((item, index, arr) => {console.log(item, index, arr);
})

// 输出
// { name: '周杰伦', num: 20 },0, [{ name: '周杰伦', num: 20 },{ name: '许嵩', num: 25 },{ name: '林俊杰', num: 19 },{ name: '蔡徐坤', num: 10 },{ name: '鹿晗', num: 0 }]
// { name: '许嵩', num: 25 },1,[{ name: '周杰伦', num: 20 },{ name: '许嵩', num: 25 },{ name: '林俊杰', num: 19 },{ name: '蔡徐坤', num: 10 },{ name: '鹿晗', num: 0 }]
// ...
// ...
// ... 

知道了 Array.forEach() 接收的参数以及怎么执行的,那么我们就可以开始手写它了。

Array.prototype.my_forEach = function(callback) {//将我们手写的方法定义在Array的原型上,接收一个callback回调for (let i = 0; i < this.length; i++) { //遍历这个数组,同时在遍历里面调用这个接收到的回调callback(this[i], i, this)}
} 

相对于其它数组遍历方法,forEach方法应该是最简单的一种方法了,没有很特殊的地方,只是简简单单的遍历数组里每一个元素,传递出来。

Array.map()

Array.map() 方法跟 Array.forEach() 方法接收的参数相似;

也是接收一个回调,回调里也是接收那三个参数,分别代表着(数组项,下标,整个数组);

但是它跟 Array.forEach() 还是有一个差别;

那就是它会返回出来一个数组,返回出来的数组的每一项都是回调里面返回出来的值。

例如:

const singer = [{ name: '周杰伦', num: 20 },{ name: '许嵩', num: 25 },{ name: '林俊杰', num: 19 },{ name: '蔡徐坤', num: 10 },{ name: '鹿晗', num: 0 },]const newSinger = singer.map((item, index, arr) => {return item})console.log(newSinger); 

打印出来的结果会是:

那么知道了 Array.map() 的特性之后,我们完全可以开始手写它了,

Array.prototype.my_map = function(callback) { // 写一个my_map方法写在Array原型上,接收一个回调const res = []//定义一个数组,用来接收遍历回调得到的新的返回值,最后返回出去for (let i = 0; i < this.length; i++) {res.push(callback(this[i], i, this))//把回调返回出来的值往res数组添加}return res //返回出去数组res
} 

Array.map() 相对于普通的遍历来说,它只是会返回出来一个数组,用来接收每个回调的返回值。

Array.filter()

Array.filter() 方法跟 Array.map() 方法接收的参数一样,也是接收一个回调;

回调里同样也是接收那三个参数,分别代表着(数组项,下标,整个数组);

同时它跟 Array.map() 一样,它也会返回出来一个数组;

但是不一样的是,它会对数组每一项进行筛选(故我们通常会叫 filter 叫筛选器方法);

筛选的条件就是回调函数里的 return 所返回出来的条件。

例如:

const singer = [{ name: '周杰伦', num: 20 },{ name: '许嵩', num: 25 },{ name: '林俊杰', num: 19 },{ name: '蔡徐坤', num: 10 },{ name: '鹿晗', num: 0 },]const newSinger = singer.filter((item, index, arr) => {return item.num > 15})console.log(newSinger);//打印结果:// [{ name: '周杰伦', num: 20 },//{ name: '许嵩', num: 25 },//{ name: '林俊杰', num: 19 }] 

这里我们用官方的 Array.filter() 方法,在里面返回的条件是 item.num>15 ;

所以我们打印用来接收 filter 返回出来的那个数组,可以看到的是打印的是:

[{ name: '周杰伦', num: 20 }, { name: '许嵩', num: 25 }, { name: '林俊杰', num: 19 }]

打印出来的这个数组里每一个元素都是满足 item.num>15 这个条件的数组项;

所以我们如果想写一个 filter 方法的话,目标就很明确了,我们需要满足:

1.遍历这个数组的同时拿回调函数里返回出来的判断条件来判定数组项是否满足条件2.满足条件的数组项我们就把它放到一个新数组里去,用于最后返回出来那么知道这些,我们就可以很轻松的把这个方法手写出来了:

Array.prototype.my_filter = function(callback) {const res = [];//定义一个空数组,用来装满足判定条件的数组项for (let i = 0; i < this.length; i++) { //遍历回调callback(this[i], i, this) && res.push(this[i]) //语句判断,如果满足回调函数返回出来的判定条件,就把数组该项加入res数组}return res//返回出来满足条件的数组
} 

Array.every()

Array.every() 方法与其它数组方法接收的参数也是基本一致,不同的是它是返回出来一个 boolean 值;

应用场景一般是发生在检查所有数组值是否通过测试;

一旦有一个值不通过,那么就会直接返回 false,只有所有值都满足条件,才会返回 true。

根据这些条件我们就可以有了大致方向:

1.对数组每一项进行条件判断,只有一个不满足,直接 return false2.循环结束后加一个 return true 用于返回当所有情况都满足了,那么返回 true```
Array.prototype.my_every = function(callback) {for(let i = 0 ; i < this.length; i++) {if(!callback(this[i],i,this)){//判定不满足的情况return false; //一旦有一个不满足,那么我们就直接返回false,不再执行接下来的代码}}return true;//当所有的元素都不返回false,那么咱们就返回true
}


Array.some()
------------

Array.some() 方法跟 Array.every() 方法刚好相反;

它也是返回出来一个 boolean 值,不同的是只要有数组里有一个元素满足判定条件,那么就会直接返回 true;

若没有一个满足条件,那么就会返回 false。

根据这些条件我们就可以往这个方向思考:

1.对数组每一项进行条件判断,只有一个满足,直接 return true2.循环结束后加一个 return false 用于返回当所有情况都不满足了,那么返回 false```
Array.prototype.my_every = function(callback) {for(let i = 0 ; i < this.length; i++) {if(callback(this[i],i,this)){//判定满足的情况return true; //一旦有一个满足,那么我们就直接返回true,不再执行接下来的代码}}return false;//当所有的元素都不返回true,那么咱们就返回false
} 

Array.reduce()

Array.reduce() 方法应该算是数组的所有的遍历方法里面比较特殊的一个方法吧;

它接收两个参数,第一个参数是需要执行的回调函数,而第二个参数则是初始的一个变量值;

这么说它的第二个参数可能大家都不太理解,没关系,待会儿会带大家仔细讲解。

再讲它的回调函数,它的回调接收四个参数:

function myFunction(pre, value, index, array) {return pre + value;
}
//四个参数分别代表着:
//- 总数(初始值/先前返回的值)
//- 项目值
//- 项目索引
//- 数组本身 

那么咱们来看一看官方给出的 Array.reduce() 的实例吧:

let arr = [1,2,3,4,5,6];

const res = arr.reduce((pre, value, index, array)=>{console.log(pre,value,index,array);return pre + value
},0)

console.log(res);

// 运行结果:
// 0 1 0 [ 1, 2, 3, 4, 5, 6 ]
// 1 2 1 [ 1, 2, 3, 4, 5, 6 ]
// 3 3 2 [ 1, 2, 3, 4, 5, 6 ]
// 6 4 3 [ 1, 2, 3, 4, 5, 6 ]
// 10 5 4 [ 1, 2, 3, 4, 5, 6 ]
// 15 6 5 [ 1, 2, 3, 4, 5, 6 ]
// 21 

我们可以看到的就是第一次 pre 的值就是我们 reduce 所接收到的第二个参数,而之后的 pre 都是上一次 pre 与 value 的和;

那么为什么是 pre 和 value 的和呢?

原因是每次 reduce 都在执行那个回调,而回填返回出来的值都会传到下一次 reduce 遍历的 pre 中;

这就是 reduce 所接收的各个参数了。

reduce 这个方法多用于数组的累加,累乘等等累积值。

那么如果不给 reduce 传第二个参数会怎样?

这是个好问题,咱们来一起看看:

可以看到的是,它的打印少了一层,那就是第一层,它从数组的第二项开始遍历,而第一个 pre 则是数组没有被遍历的第一项。

所以由此可知,如果我们不给 reduce 传第二个参数,那么它就会默认从数组第二项开始遍历,而第一个 pre 则会变成数组第一项。

那么要手写 reduce 这个方法,我们需要做到哪些条件呢?

1.判断 reduce 是否有接收到第二个参数,做情况判断,决定开始从数组哪个位置开始遍历;2.把每一次回调 return 出来的值都传给下一次回调的 pre ;3.把回调里最后一次 return 传出去。有了这个方向咱们就可以开始手写了:

Array.prototype.my_reduce = function(callback, ...args) {let pre, start = 0;// 定义一个 pre ,方便把最后一次 pre 传出去;if (args.length) {// 判断是否存在第二个参数,决定数组从下标0,还是下标1开始遍历,同时给第一次 pre 赋值pre = args[0]} else {pre = this[0]start = 1}for (let i = start; i < this.length; i++) { // 遍历调用回调,把每一次 pre 传到下一次pre = callback(pre, this[i], i, this)}return pre// 把最后的 pre 传出去} 

那么最后的 Array.reduce() 也写完了,数组的遍历方法手写也就到此为止啦。

最后

最近找到一个VUE的文档,它将VUE的各个知识点进行了总结,整理成了《Vue 开发必须知道的36个技巧》。内容比较详实,对各个知识点的讲解也十分到位。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Elasticsearch在Linux中的单节点部署和集群部署

目录一、Elasticsearch简介二、Linux单节点部署1、软件下载解压2、创建用户3、修改配置文件4、切换到刚刚创建的用户启动软件5、测试三、Linux集群配置1、拷贝文件2、修改配置文件3、分别修改文件所有者4、启动三个软件5、测试四、问题总结1、在elasticsearch启动时如果报错内存…

【黑盒模糊测试】路由器固件漏洞挖掘实战--AFL++ qemu_mode

前言 很久之前就想写AFL++的qemu_mode了,只是模糊测试专题的文章有些过于耗费时间,加上工作原因导致一直搁置。最近需要出差会用到黑盒模糊测试,所以就当做复习一遍,我记得Fuzzing 101也有一个qemu_mode的练习,有空的话下一篇文章更新吧~ 编写不易,如果能够帮助到你,希望…

金三银四软件测试面试如何拿捏面试官?【接口测试篇】

九、接口测试 9.1 接口测试怎么测 &#xff08;jmeter版本&#xff09; 首先开发会给我们一个接口文档&#xff0c;我们根据开发给的接口文档&#xff0c;进行测试点的分析&#xff0c;主要是考虑正常场景与异常场景&#xff0c;正常场景&#xff0c;条件的组合&#xff0c;…

前端vue实现获取七天时间和星期几功能

前端vue实现获取七天时间和星期几功能 功能展示代码 <div v-for"(item,index) in same_week" :class"[same_dayitem.date? activ :,dis]" click"select(item)" :keyindex><span>{{item.name}}</span><span>{{item.…

[技术经理]01 程序员最优的成长之路是什么?

00前言 谈起程序员的职业规划&#xff0c;针对大部分的职场人士&#xff0c;最优的成长之路应该是走技术管理路线&#xff0c;而不是走技术专家路线。 01关键的一步 中国自古就有“学而优则仕”的传统&#xff0c;发展到今天&#xff0c;在我们的现代企业里面&#xff0c;尤…

【JavaEE初阶】第一节.多线程(进阶篇 ) 常见的锁策略、CAS及它的ABA问题

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、常见的锁策略 1.1 乐观锁 vs 悲观锁 1.2 普通的互斥锁 vs 读写锁 1.3 重量级锁 vs 轻量级锁 1.4 自旋锁 vs 挂起等待锁 1.5 公平…

Mac - Spotlight(聚焦)

文章目录一、Mac 中 Spotlight 的使用1、调用/打开 Spotlight2、执行搜索3、Spotlight 设置二、Mac 上的 Spotlight 开发1、关于 Spotlight2、使用 NSMetadataQuery 搜索示例三、mds 和 fsevents四、命令行访问 Spotlight五、Core Spotlight Framework六、Spotlight 插件相关资…

拼多多订单查询

下载地址webcrawl最新版本下载、安装、运行教程使用场景场景一我有很多个拼多多的买家号&#xff0c;想通过一个订单编号&#xff0c;查询该订单的各种信息&#xff0c;如订单状态&#xff0c;收件信息&#xff0c;物流信息&#xff0c;售后信息&#xff0c;联系商家场景二有很…

unix高级编程-fork和execve

fork和vfork vfork是老的实现方法又很多问题 vfork #include <sys/types.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <signal.h> #include <errno.h> #include <sys/stat.…

AQS-ReentrantLock

一、AQS 在 Lock 中&#xff0c;用到了一个同步队列 AQS&#xff0c;全称 AbstractQueuedSynchronizer&#xff0c;它是一个同步工具&#xff0c;也是 Lock 用来实现线程同步的核心组件。 1.AQS 的两种功能 独占和共享。 独占锁&#xff1a;每次只能有一个线程持有锁&#x…

Git 分支操作

1&#xff1a;什么是分支几乎所有的版本控制系统都以某种形式支持分支。 使用分支意味着你可以把你的工作从开发主线上分离 开来进行重大的Bug修改、开发新的功能&#xff0c;以免影响开发主线。 几乎所有的版本控制系统都以某种形式支持分支。 使用分支意味着你可以把你的工作…

2023“Java基础-中级-高级”面试集结,已奉上我的膝盖

Java基础&#xff08;对象线程字符接口变量异常方法&#xff09; 面向对象和面向过程的区别&#xff1f; Java 语言有哪些特点&#xff1f; 关于 JVM JDK 和 JRE 最详细通俗的解答 Oracle JDK 和 OpenJDK 的对比 Java 和 C的区别&#xff1f; 什么是 Java 程序的主类&…

GLOG如何控制输出的小数点位数

1 问题 在小白的蹩脚翻译演绎型博文《GLOG从入门到入门》中&#xff0c;有位热心读者提问说&#xff1a;在保存日志时&#xff0c;浮点型变量的小数位数如何设置&#xff1f; 首先感谢这位“嘻嘻哈哈的地球人”赏光阅读了小白这不太通顺的博客文章&#xff0c;并提出了一个很…

红旗语音助手HMI设计流程之调研篇

红旗智能语音助手是基于红旗4.0智能化平台打造的场景设计研究成果。本篇文章&#xff0c;将会以红旗语音助手为例&#xff0c;带领小伙伴们了解一下HMI设计中的调研工作。在项目中&#xff0c;我们需要要通过多模态的调研手段&#xff0c;去分辨用户的哪些需求是真需求&#xf…

【C++】string类的基本使用

层楼终究误少年&#xff0c;自由早晚乱余生。你我山前没相见&#xff0c;山后别相逢… 文章目录一、编码&#xff08;ascll、unicode字符集、常用的utf-8编码规则、GBK&#xff09;1.详谈各种编码规则2.汉字在不同的编码规则中所占字节数二、string类的基本使用1.string类的本质…

Hive---Hive语法(一)

Hive语法&#xff08;一&#xff09; 文章目录Hive语法&#xff08;一&#xff09;Hive数据类型基本数据类型&#xff08;与SQL类似&#xff09;集合数据类型Hive数据结构数据库操作创建库使用库删除库表操作创建表指定分隔符默认分隔符&#xff08;可省略 row format&#xff…

逆向工具之 unidbg 执行 so

1、unidbg 入门 unidbg 是一款基于 unicorn 和 dynarmic 的逆向工具&#xff0c; 可以直接调用 Android 和 IOS 的 so 文件&#xff0c;无论是黑盒调用 so 层算法&#xff0c;还是白盒 trace 输出 so 层寄存器值变化都是一把利器&#xff5e; 尤其是动态 trace 方面堪比 ida tr…

零基础机器学习做游戏辅助第十四课--原神自动钓鱼(四)yolov5目标检测

一、yolo介绍 目标检测有两种实现,一种是one-stage,另一种是two-stage,它们的区别如名称所体现的,two-stage有一个region proposal过程,可以理解为网络会先生成目标候选区域,然后把所有的区域放进分类器分类,而one-stage会先把图片分割成一个个的image patch,然后每个im…

关于SqlServer高并发死锁现象的分析排查

问题描述 通过定期对生产环境SqlServer日志的梳理&#xff0c;发现经常会出现类似事务与另一个进程被死锁在资源上&#xff0c;并且已被选作死锁牺牲品&#xff0c;请重新运行该事务的异常&#xff0c;简单分析一下原因&#xff1a;在高并发场境下&#xff0c;多个事务同时对某…

Ubuntu 使用Nohup 部署/启动/关闭程序

目录 一、什么是nohup&#xff1f; 二、nohup能做什么&#xff1f; 三、nohup如何使用&#xff1f; 四、怎么查看/关闭使用nohup运行的程序&#xff1f; 命令 实例 一、什么是nohup&#xff1f; nohup 命令运行由 Command参数和任何相关的 Arg参数指定的命令&#xff0c…