JavaScript--ES5数组新增方法(forEach、filter、every、some、reduce、reduceRight)的用法与原码实现

本文主要是介绍JavaScript--ES5数组新增方法(forEach、filter、every、some、reduce、reduceRight)的用法与原码实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

ES5数组方法(forEach、filter、every、some、map、reduce、reduceRight)的用法

在讲原码实现之前,先将各个API的用法。这里我先放一个数组,以便后续使用~~
<script>var dataArr = [{name: "John", des: '全网最帅', sex: 'boy', age: 18, grade: 80},{name: "sunny", des: '比刘宝宝丑那么点', sex: 'boy', age: 30, grade: 100},{name: "MrDeng", des: '比成哥丑那么点', sex: 'boy', age: 45, grade: 100},{name: "cst", des: '全网最丑', sex: 'boy', age: 26, grade: 100},{name: "chang", des: '全网最矮', sex: 'girl', age: 18, grade: 80},{name: "Monikatx", des: '全网最美', sex: 'girl', age: 20, grade: 100},];
</script>

1.forEach

    dataArr.forEach(function (item, index, self){this[index].innerText = item.name;}, dom);

点击这里(forEach详细API)

forEach必须要传一个匿名函数作为实参,第二个参数是可选参数,讲用作改变匿名函数的this。
forEach的作用,可以看做是加强的for循环,用来遍历数组
forEach之所以是看做是加强版的for循环,就是因为他也是一个循环。所发挥的作用也for相差无几,底层也是利用的for循环。那他到底是怎么循环的呢?遍历数组length长度多长,这里的第一个实参,匿名函数就执行几次,而形参也会跟着被遍历。

这里我先说下匿名函数形参(形参是可以随意命名的,可以选择自己喜欢的名字):

    形参一: item  代表的所遍历数组的value值, 如:arr[0] = "刘宝宝" ,"刘宝宝"是value值。形参二: index 代表的所遍历数组的key值(索引), 如:arr[0] = "刘宝宝" ,[0]是key值。形参二: self 代表的所遍历数组自己, 如:arr[0] = "刘宝宝" ,arr是self值。

forEach传的匿名函数会自己调用,而第二个实参,将被作为匿名函数的this传入 ,如:

这里写图片描述
之后6个方法原理是一样的,之后我就不在重复述说了

2.filter

  // filtervar younger = dataArr.filter(function (item, index, self){let flag = item.age < 25;this[index].innerText += ( flag  ?  " baby" : " old");return flag;}, dom)console.log(younger);//输出[{name: "John"...}, {name: "chang"}, {name: "Monikatx"}]

filter与forEach 传参相同,必须要传一个匿名函数作为实参,可选择传一个值作为this。匿名函数的形参也与forEach 的匿名函数相同。请参考forEach 。

这里主要说说filter的功能:执行完成返回一个数组,我这里用younger接收。执行匿名函数内的代码时,返回一个boolean值判断真假,若不是布尔值返回给filter,filter自己将做隐式转化为布尔值判断真假。当返回值return 为真(true),将该次遍历的数组添加到younger。反之false舍弃,不添加。

3.every

 // every 当遇上false停止遍历var flagEvery = dataArr.every(function (item, index, self){console.log(item.grade);return item.grade > 90 ? true : false;}, dom)console.log(flagEvery);

every与forEach 传参相同,必须要传一个匿名函数作为实参,可选择传一个值作为this。匿名函数的形参也与forEach 的匿名函数相同。请参考forEach 。

every的功能:执行完成返回一个布尔值。执行匿名函数内的代码时,返回一个boolean值判断真假,若不是布尔值返回给every。当所有返回值return 为真,返回真(true),只要有一个不为真(true)返回假(false)。

4.some

// some 遇上true停止遍历
var flagSome = dataArr.some(function (item, index, self){console.log(item.grade);return item.grade > 90 ? true : false;
}, dom)
console.log(flagSome);

some与forEach 传参相同,必须要传一个匿名函数作为实参,可选择传一个值作为this。匿名函数的形参也与forEach 的匿名函数相同。请参考forEach 。

some的功能:执行完成返回一个布尔值。执行匿名函数内的代码时,返回一个boolean值判断真假,若不是布尔值返回给some。当所有返回值return 有一个为真(true),返回true,全为假(false)返回假(false)。

5.map

// map 映射
var newAge = dataArr.map(function (item, index, self){// return item.age + 10;item.age += 10;return item;
}, dom)
console.log(newAge);

map与forEach 传参相同,必须要传一个匿名函数作为实参,可选择传一个值作为this。匿名函数的形参也与forEach 的匿名函数相同。请参考forEach 。

map的功能:执行完成返回一个新的数组。执行匿名函数内的代码时,将该次遍历的返回值添加到新数组中。这段代码中我写了两段return,第一段return改变的是对象里的属性,并返回该属性值,这里返回的是原始值,和之前的的数组将没有联系。第二段return改变的也是对象里的属性,但返回的是对象本身,对象是引用值。如果你对新数组里的对象进行操作,原素组里的对象也将发生改变

6.reduce

// reduce
var allName = dataArr.reduce(function (prev, current, index, self) {return prev + current.name;
}, '+');
console.log(allName)

reduce这里需要注意,和forEach有点传参有些不一样了,第一个实参也是匿名函数,自行调用。这第二个实参也是可选参数,可传可不传,但是作用不一样。forEach是传一个实参作为this,而reduce的第二个实参是初始值。具体看下面~~

reduce的匿名函数形参:

  1. 形参一: prev 代表的所遍历数组索引位的上一个索引位匿名函数的返回值。若当前索引位为0,先看reduce有没有第二实参,也就是我上面所说的初始值。有,将初始值给prev。无,prev为空。
  2. 形参二: current 代表的所遍历数组的value值, 如:arr[0] = “刘宝宝” ,”刘宝宝”是value值。
  3. 形参三: index 代表的所遍历数组的key值(索引), 如:arr[0] = “刘宝宝” ,[0]是key值。
  4. 形参四: self 代表的所遍历数组自己, 如:arr[0] = “刘宝宝” ,arr是self值。

reduce的功能:执行完成返回一个返回值。执行匿名函数内的代码时,执行匿名函数内的代码块。返回一个返回值,但这个返回值不是给reduce自己用的,而是给自己下一个遍历数组索引位下一个匿名函数形参prev赋值的。最后一个索引位匿名函数的返回值才是reduce的返回值。

7.reduceRight

// reduceRightvar allNameBack = dataArr.reduceRight(function (prev, current, index, self) {return prev + current.name;}, '-')console.log(allNameBack)

reduceRight与reduce其实差不多,区别在于他的遍历顺序是反过来的。细节没什么好说的,不懂的可以参考reduce

reduceRight的功能:执行完成返回一个返回值。执行匿名函数内的代码时,执行匿名函数内的代码块。返回一个返回值。reduceRight遍历是从数组最后一位开始遍历,初始也是给的最后数组索引位匿名函数的形参prev。返回值是索引位 [0] 匿名函数的返回值。


好了,本文到此就结束了~~
期待下一次更新吧!!

好吧,我是真想睡了。写到这已经是将近凌晨4点半了。但我还是坚持写完,整篇没看到我皮,是不是不适应??不是不想皮,是实在太困了。

接下来是用js原码自己封装7种ES5数组方法——–


ES5数组方法(forEach、filter、every、some、map、reduce、reduceRight)的原码实现

1.myForEach

Array.prototype.myForEach = function (fn) {var i, _self = this, len = _self.length, target = arguments[1];for(i = 0; i < len; i++) {fn.apply(target, [_self[i], i, _self]);}
}

既然是数组方法,那就要封装在Array.prototype上。Array.prototype.myForEach = function () {fn},这里的函数表达式执行就是arr.myForEach ()。按道理这么基础的东西,我本不应该再讲,但考虑到,我同学在听课的时候已经被绕晕了,所以是讲一下。这里的 fn 是形参,那执行就是arr.myForEach (function () {}), fn 就是这个里面的实参(匿名函数了)。可能你们会有疑惑,那dom作为第二个实参,在这怎么没看到与之对应的形参呢?我只看到一个形参!!!来来,接下来给你看一下第二个形参在哪里。不应该叫形参了,得叫实参列表这里写图片描述

这里通过argument[1]来获取第二个实参,也就是dom。而之前说的foreach第二个实参将成为匿名函数的this,就是在这了apply将匿名函数fn的this指向dom,并传入三个形参,变量名i, _self, len, 分别是指遍历的索引,被遍历的数组本身也就是arr, len是数组的长度arr.length,而这里面的for相信你们也能看懂,让匿名函数fn执行len-1次。希望你们不要再被 myForEachfn 给绕晕,我已经尽我最大的能力来讲了。下面的我就不再这么讲了

2.myFilter

 // 封装myFilter
Array.prototype.myFilter = function (fn) {var i, _self = this, len = _self.length, target = arguments[1], newArr = [];for(i = 0; i < len; i++) {fn.apply(target, [_self[i], i, _self]) ? newArr.push(_self[i]) : '像刘宝宝这么帅的人不多了';}return newArr;
}

有没有发现myFilter 和myForEach长竟然如此相像,先不要惊讶,因为在后面你会发现,这7个方法都长的差不多。

这里myFilter 比myForEach多了一个newArr数组,和一个return。这是因为filter是有返回值的,这个返回值也得是一个数组。之前说过filter每次遍历的匿名函数fn都会返回一个值给filter判断,这里for循环内fn.apply就是一次执行,执行后的返回值用作三目运算符判断,返回值为true,newArr添加当前数组索引位_self[i]。
然而这里后面这串字符串才是本文的重点。来来,圈起来,这是重点考试肯定是要考的。
emm,既然是筛选,那么为false就不要它执行任何操作就好了,但是三目运算符是你fasle也要有个表达式,那我就填个空就好了,但是这样不能表现出我的文笔功底,才会引出这么有哲学的一句话。令人反思啊。。。
最后遍历完了,就要返回数组,return newArrr。

3.myEvery

// 封装myEveryArray.prototype.myEvery = function (fn) {var i, _self = this, len = _self.length, target = arguments[1], flag = true;for(i = 0; i < len; i++) {if(!fn.apply(target, [_self[i], i, _self])){flag = false;break;} }return flag;}

是的,我是个诚实的宝宝。你看是不是长得相差不大?

myEvery返回的是true或false。所以开头声明一个flag=true,接下来我只需要遍历出匿名函数fn不是true,让flag=false就好了,当然既然只要是有一个不为true,every就要返回false,那你匿名函数fn返回给我false。我干脆就不遍历了,让你出去吧。免得还让我做无用功,break退出块级作用域,块级作用域不知道的我这里也不说了。最后返回flag为false,当然你匿名函数给我的返回值全是true,那我根本没走if里,自然flag就是true了。

4.mySome

// 封装mySome
Array.prototype.mySome = function (fn) {var i, _self = this, len = _self.length, target = arguments[1], flag = false;for(i = 0; i < len; i++) {if(fn.apply(target, [_self[i], i, _self])){flag = true;break;} }return flag;
}

这一块呢,我就不讲了。你只要看懂上面的,下面的你一定能看懂。

mySome返回布尔值。是的,就这么简短~~不服?不服你来打我啊!!

5.myMap

// 封装myMapArray.prototype.myMap = function (fn) {var i, _self = this, len = _self.length, target = arguments[1], newArr = [];for(i = 0; i < len; i++) {newArr.push(fn.apply(target, [_self[i], i, _self]));// 这里可以使用深度克隆,让返回值是引用值也区分开来}return newArr;}

myMap也没什么好讲的,就是声明一个数组,匿名函数操作完添加,返回数组。

myMap返回数组。是的,还是就这么简短~~不服?不服你又能怎样呢!!

6.myReduce

// 封装myReduce
Array.prototype.myReduce = function (fn) {var i, _self = this, len = _self.length, initValue = arguments[1];for(i = 0; i < len; i++) {initValue = fn(initValue, _self[i], i, _self);}return initValue;
}

myReduce也没什么好讲的。。。。。。但是我的求生欲告诉我这里还是要讲的。

myReduce的实参列表arguments[1]第二个实参不再是改变匿名函数(fn) this指向,而是直接作为匿名函数fn的第一个实参传入,传进去干嘛呢?之前说了reduce索引位是0的时候,他是没有上一返回值的,所以讲第二个实参传入作为初始值,也就是索引位是0的的上一个返回值。 initValue = fn(initValue, _self[i], i, _self);这样写是让初始值initValue(也就是当前索引返回值)赋值为下一个索引位的匿名函数fn使用(prev)。到for循环遍历完initValue也就被赋值成最后一位索引匿名函数fn的返回值;

6.myReduceRight

 // 封装myReduceRight
Array.prototype.myReduceRight = function (fn) {var i, _self = this, len = _self.length, initValue = arguments[1];for(i = len-1; i >= 0; i--) {console.log(i)initValue = fn(initValue, _self[i], i, _self);}return initValue;
}

myReduceRight也讲讲吧。

myReduceRight是反序遍历,那for循环也就要反向遍历,for(i = len-1; i >= 0; i–)。
好了,讲完了~~


最后,本文到这里就结束了。首先,有疑惑或者我哪里讲的不对,麻烦大家指正,我写文章纯属是来了兴趣就写上一篇,担心给大家带来误导。其次,感谢大家的支持,上次文章的阅读量给了我很大的激励,两天就200多阅读量,这使我膨胀了,我膨胀到自己都不认识了,我要飞上天和太阳肩并肩~~

这篇关于JavaScript--ES5数组新增方法(forEach、filter、every、some、reduce、reduceRight)的用法与原码实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/276161

相关文章

SpringBoot3实现Gzip压缩优化的技术指南

《SpringBoot3实现Gzip压缩优化的技术指南》随着Web应用的用户量和数据量增加,网络带宽和页面加载速度逐渐成为瓶颈,为了减少数据传输量,提高用户体验,我们可以使用Gzip压缩HTTP响应,... 目录1、简述2、配置2.1 添加依赖2.2 配置 Gzip 压缩3、服务端应用4、前端应用4.1 N

Linux换行符的使用方法详解

《Linux换行符的使用方法详解》本文介绍了Linux中常用的换行符LF及其在文件中的表示,展示了如何使用sed命令替换换行符,并列举了与换行符处理相关的Linux命令,通过代码讲解的非常详细,需要的... 目录简介检测文件中的换行符使用 cat -A 查看换行符使用 od -c 检查字符换行符格式转换将

Java编译生成多个.class文件的原理和作用

《Java编译生成多个.class文件的原理和作用》作为一名经验丰富的开发者,在Java项目中执行编译后,可能会发现一个.java源文件有时会产生多个.class文件,从技术实现层面详细剖析这一现象... 目录一、内部类机制与.class文件生成成员内部类(常规内部类)局部内部类(方法内部类)匿名内部类二、

SpringBoot实现数据库读写分离的3种方法小结

《SpringBoot实现数据库读写分离的3种方法小结》为了提高系统的读写性能和可用性,读写分离是一种经典的数据库架构模式,在SpringBoot应用中,有多种方式可以实现数据库读写分离,本文将介绍三... 目录一、数据库读写分离概述二、方案一:基于AbstractRoutingDataSource实现动态

Python FastAPI+Celery+RabbitMQ实现分布式图片水印处理系统

《PythonFastAPI+Celery+RabbitMQ实现分布式图片水印处理系统》这篇文章主要为大家详细介绍了PythonFastAPI如何结合Celery以及RabbitMQ实现简单的分布式... 实现思路FastAPI 服务器Celery 任务队列RabbitMQ 作为消息代理定时任务处理完整

揭秘Python Socket网络编程的7种硬核用法

《揭秘PythonSocket网络编程的7种硬核用法》Socket不仅能做聊天室,还能干一大堆硬核操作,这篇文章就带大家看看Python网络编程的7种超实用玩法,感兴趣的小伙伴可以跟随小编一起... 目录1.端口扫描器:探测开放端口2.简易 HTTP 服务器:10 秒搭个网页3.局域网游戏:多人联机对战4.

Springboot @Autowired和@Resource的区别解析

《Springboot@Autowired和@Resource的区别解析》@Resource是JDK提供的注解,只是Spring在实现上提供了这个注解的功能支持,本文给大家介绍Springboot@... 目录【一】定义【1】@Autowired【2】@Resource【二】区别【1】包含的属性不同【2】@

springboot循环依赖问题案例代码及解决办法

《springboot循环依赖问题案例代码及解决办法》在SpringBoot中,如果两个或多个Bean之间存在循环依赖(即BeanA依赖BeanB,而BeanB又依赖BeanA),会导致Spring的... 目录1. 什么是循环依赖?2. 循环依赖的场景案例3. 解决循环依赖的常见方法方法 1:使用 @La

Java枚举类实现Key-Value映射的多种实现方式

《Java枚举类实现Key-Value映射的多种实现方式》在Java开发中,枚举(Enum)是一种特殊的类,本文将详细介绍Java枚举类实现key-value映射的多种方式,有需要的小伙伴可以根据需要... 目录前言一、基础实现方式1.1 为枚举添加属性和构造方法二、http://www.cppcns.co

使用Python实现快速搭建本地HTTP服务器

《使用Python实现快速搭建本地HTTP服务器》:本文主要介绍如何使用Python快速搭建本地HTTP服务器,轻松实现一键HTTP文件共享,同时结合二维码技术,让访问更简单,感兴趣的小伙伴可以了... 目录1. 概述2. 快速搭建 HTTP 文件共享服务2.1 核心思路2.2 代码实现2.3 代码解读3.