前言
如果对技术很自信, 请直接看 实现的源码
如果想回顾一下基础, 请按文章顺序阅读
说到迭代方法, 最先想到的是什么? forEach 还是 map, 迭代的方法 ES5 提供了 5 种方法
以下定义来自 JavaScript 高级程序设计
每个方法都接收两个参数
在每一项上运行的函数
运行该函数的作用域对象 (影响 this 的值)
传入这些方法中的函数会接收 3 个参数
数组项的值
该项在数组的位置
数组对象本身
迭代函数执行后可能会也可能不会影响返回结果 (雾..)
ES5 提供的迭代函数
forEach(): 对数组中的每一项运行给定函数, 无返回值
every(): 对数组中的每一项运行给定函数, 如果该函数每一项都返回 true, 则返回 true
some(): 对数组中的每一项运行给定函数, 如果该函数任意一项返回 true, 则返回 true
map(): 对数组中的每一项运行给定函数, 返回每次函数调用的结果组成的数组
filter(): 对数组中的每一项运行给定函数, 该函数会返回 true 的项组成的数组
参数说明
- let array = [1,2,3,4,5,6,7,8,9]
- array.forEach((element,index,array) => {
- console.log(` 当前遍历元素 ${element}`);
- console.log(` 当前元素位置 ${index}`);
- console.log(` 数组本身 ${array}`);
- })
> 当前遍历元素 1
> 当前元素位置 0
> 数组本身 1,2,3,4,5,6,7,8,9
> 当前遍历元素 2
> 当前元素位置 1
> 数组本身 1,2,3,4,5,6,7,8,9
> 当前遍历元素 3
> 当前元素位置 2
> 数组本身 1,2,3,4,5,6,7,8,9
forEach 可以说是最常用的一个迭代方法了, 该方法没有返回值, 与 for 循环的效果一样
forEach 的第二个参数, JS 高程上说明 是运行该函数的作用域对象, 可以看一下经典的例子
- let obj2 = {
- name: '张三',
- times:[1,2,3],
- print:function () {
- this.times.forEach(function(res) {
- console.log(this.name);
- },this)
- }
- }
- // 迭代函数内部的 function 默认指向 Windows 第二个参数调整了 this 指向
- obj2.print()
- // 张三
- // 张三
- // 张三
如果这么写看不太懂的话, 看箭头函数的写法一下子就能明白
- let obj2 = {
- name: '张三',
- times:[1,2,3],
- print:function () {
- this.times.forEach(res => {
- console.log(name);
- })
- }
- }
- // 箭头函数 this 指向父级, 所以他不需要调整 this
- obj2.print()
- // 张三
- // 张三
- // 张三
every(判断函数)
对数组中的每一项运行给定函数, 如果该函数每一项都返回 true, 则返回 true
默认返回 false
- var array = [1,2,3,4,5,6,7,8,9]
- var result = array.every(e => {
- })
- console.log(result); //
- > false
全部 ture 才会返回 true
- var array = [1,2,3,4,5,6,7,8,9]
- var result = array.every(e => {
- return e> 0
- })
- console.log(result);
- > true
- var array = [1,2,3,4,5,6,7,8,9]
- var result = array.every(e => {
- return e> 1
- })
- console.log(result);
- > false
some(判断函数)
对数组中的每一项运行给定函数, 如果该函数任意一项返回 true, 则返回 true
默认返回 false
- var array = [1,2,3,4,5,6,7,8,9]
- var result = array.some(e => {
- })
- console.log(result); //
- > false
全部 false 才会返回 false
- var array = [1,2,3,4,5,6,7,8,9]
- var result = array.some(e => {
- return e> 8
- })
- console.log(result);
- var array = [1,2,3,4,5,6,7,8,9]
- var result = array.some(e => {
- return e> 9
- })
- console.log(result);
- > false
以上两个都不是很常用, 但是毫无疑问在特定的需求下, 这个要比用 forEach 代码要简洁很多
filter(过滤函数)
对数组中的每一项运行给定函数, 该函数会返回 true 的项组成的数组
- var array = [1,2,3,4,5,6,7,8,9]
- var result = array.filter(e => {
- return e>5
- })
- console.log(result);
- > [6, 7, 8, 9]
上面的例子, array 数组里面大于 5 的数会被过滤出来, filter 函数在日常当中比较常用
map(处理函数)
对数组中的每一项运行给定函数, 返回每次函数调用的结果组成的数组
- var array = [1,2,3,4,5,6,7,8,9]
- var result = array.map(e => {
- return e>5
- })
- console.log(result);
- > [false, false, false, false, false, true, true, true, true]
- var array = [1,2,3,4,5,6,7,8,9]
- var result = array.map(e => {
- return e*2
- })
- console.log(result);
- > [2, 4, 6, 8, 10, 12, 14, 16, 18]
forEach(迭代函数)
对数组中的每一项运行给定函数, 无返回值
- var array = [1,2,3,4,5,6,7,8,9]
- var arraypush = []
- var result = array.forEach(e => {
- if (e> 5) {
- arraypush.push(e)
- }
- })
- console.log(arraypush);
- > [6, 7, 8, 9]
最纯粹的迭代函数, 似乎 forEach 是处理外部数组最好的选择
到这里, 我想起了我第一次使用 filter 函数的时候, 我惊呆了, 这函数太强大了!
如此好用的工具函数, 不自己实现一遍怎么能做到完全了解
以下函数为自己实现的, 并不是源码, 若有错误请指点!
实现 forEach
首先明显 forEach 是 Array 上的原型链上的函数所以第一件事就是创建一个原型方法
Array.prototype.MyforEach = function (){}
forEact 第一个参数为一个匿名函数 第二个参数为 this 指向 所以
Array.prototype.MyforEach = function (fn,obj){}
forEach 会迭代调用它的数组所以内部肯定是循环
- Array.prototype.MyforEach = function (fn,obj){
- let len = this.length
- for (let index = 0; index <len; index++) {
- fn(this[index],index,this)
- }
- }
但是我们还没有考虑 this 指向的事情, 所以还需要添加一些调整 this 的代码
- Array.prototype.MyforEach = function (fn,obj){
- let len = this.length
- if (obj !== 'undefined') {
- fn = fn.bind(obj)
- }
- for (let index = 0; index < len; index++) {
- fn(this[index],index,this)
- }
- }
运行一下试试, 就用之前的例子
- var array = [1,2,3,4,5,6,7,8,9]
- Array.prototype.MyforEach = function (fn,obj){
- let len = this.length
- if (obj !== 'undefined') {
- fn = fn.bind(obj)
- }
- for (let index = 0; index < len; index++) {
- fn(this[index],index,this)
- }
- }
- var obj2 = {
- name: '张三',
- times:[1,2,3],
- print:function () {
- this.times.MyforEach(function(res) {
- console.log(this.name);
- },this)
- }
- }
- obj2.print()
> 张三
> 张三
> 张三
实现 map
map 与 forEach 的区别是
map 中如果是运算, 会返回每次函数调用的新的结果组成的数组
map 中如果是判断, 会返回每次迭代结果组成的数组
所以只要在迭代函数内部创建一个数组, 每次迭代都 push 进去, 最后返回出去就好啦
- Array.prototype.Mymap = function (fn,obj){
- var resultData = []
- var len = this.length
- if (obj !== 'undefined') {
- fn = fn.bind(obj)
- }
- for (let index = 0; index <len; index++) {
- resultData.push(fn(this[index],index,this))
- }
- return resultData
- }
运行一下
- var array = [1,2,3,4,5,6,7,8,9,]
- var result = array.Mymap(e => {
- return e*2
- })
- console.log(result);
- > [2, 4, 6, 8, 10, 12, 14, 16, 18]
实现 some every
some 与 every 都会有一个特点 默认返回 false
不同的地方在于
some 要求 全部返回 false 返回 false
every 要求 全部返回 true 返回 true
- // -- every --
- Array.prototype.Myevery = function (fn,obj) {
- var len = this.length
- if (obj !== 'undefined') {
- fn = fn.bind(obj)
- }
- for (let index = 0; index <len; index++) {
- if (fn(this[index],index,this) == undefined) { // 无返回值 默认返回 false
- return false
- }else if (fn(this[index],index,this) !== true) { // 出现一个不为 true 就停止迭代 返回结果
- return false
- }
- }
- return true
- }
- // -- some --
- Array.prototype.Mysome = function (fn,obj) {
- var len = this.length
- if (obj !== 'undefined') {
- fn = fn.bind(obj)
- }
- for (let index = 0; index < len; index++) {
- if (fn(this[index],index,this) == undefined) {
- return false
- } else if (fn(this[index],index,this) !== false) {
- return true
- }
- }
- return false
- }
实现 fliter
相信到这里, 你也可以直接实现一个 fliter 函数了, 仅仅是多添加一个数组
- Array.prototype.Myfilter = function (fn, obj) {
- let resultData = []
- var len = this.length
- if (obj !== 'undefined') {
- fn = fn.bind(obj)
- }
- for (let index = 0; index < len; index++) {
- if (fn(this[index],index,this) === true) {
- resultData.push(this[index]) // 注意不是 push 函数结果
- }
- }
- return resultData
- }
- // -- 运行 --
- var array = [1,2,3,4,5,6,7,8,9]
- var result = array.Myfilter(e => {
- return e>5
- })
- console.log(result);
- > [6, 7, 8, 9]
perfect! :stuck_out_tongue_closed_eyes:
原来很多东西, 并没有想象的那么复杂
后记
想起了之前掘金上的 停止学习框架 一文, 以及后面各位大佬的 驳 .... 停止学习框架, 说到底都是为了告诉我们, 不管学习什么, 都要打好基础, 作为前端开发者, 最最基础的就是打好 JavaScript 的基础, 基础扎实, 学习框架都不是困难事情
来源: https://juejin.im/post/5c331657e51d4551e325d6b4