概述
前言
每次看到大佬在处理数据的时候,es6789加各种高阶函数一顿操作,3行代码就解决了自己哼哧哼哧下来写了十几行代码才能完成的功能,就在心里暗自流泪,默默发四有一天我也一定要成为大佬,终于。。。这一天要来临了!
正文
一、高阶函数——Map
-
首先认识一下map函数是什么?
MDN官方介绍:map()方法是一个数组的高阶函数,接受一个带有返回值的函数,使得数组的每一个元素都会调用这个指定的方法后形成一个新数组,但不改变原数组。 -
map函数的描述
let a = [1, 2, 3, 4] let b = a.map(function (value, index, array) { return value * 2 },thisArg) console.log(b);//[2, 4, 6, 8]
map函数接收两个参数
- 必选——callback函数 ,函数内部函数 每个处理元素后的结果,最终组成一个新数组。接收三个参数其中:
- value(必选):指正在处理的元素
- index(可选):指正在处理的元素的索引
- array(可选):指被处理的数组
- 可选——thisArg:指的是函数内部this的指向。根据下面例子可以看出,如果没有传第二个参数时,map的内部this指向window,传了参数后this指向改变为所传的参数。
let array = [1,2,3,4] let b = array.map(function (value, index, array) { console.log(this,1);//Window return value * 2 }) let d = array.map(function (value, index, array) { console.log(this,2);//[1,2,3,4] return value * 2 },array) let f = array.map(function (value, index, array) { console.log(this,3); // [] return value * 2 },[])
我们接下来再看下一下这个例子
let a = [1, 2, 3, 4] let b = a.map(function (value, index, array) { a.push(5) console.log(a);//[1, 2, 3, 4, 5,5,5,5] return value * 2 }) console.log(b);//[2, 4, 6, 8]
这次我在map函数中给原数组添加了新元素,但是最终返回结果却没有跟着变化,那我们如果删除原数组中的元素返回结果还会是之前的吗?
let a = [1, 2, 3, 4] let b = a.map(function (value, index, array) { a.shift() console.log(a);// [2, 3, 4]---> [3 ,4] return value * 2 }) console.log(b);//[2, 6, undefined, undefined]
在函数内部循环删除了原数组的首个元素,返回结果发生了改变,综上理解一下这个过程:
- 在 map 方法执行的过程中:原数组中新增加的元素将不会被 callback 访问到。
- 若已经存在的元素被改变或删除了,则它们的传递到 callback 的值是 map 方法遍历到它们的那一时刻的值;而被删除的元素将不会被访问到。
- 使用 map 方法处理数组时,数组元素的范围是在 callback 方法第一次调用之前就已经确定了。
下面我们就开始结合es6相来处理数据
- 必选——callback函数 ,函数内部函数 每个处理元素后的结果,最终组成一个新数组。接收三个参数其中:
-
map函数的应用
- 格式化数组中的对象
let kvArray = [{key: 1, value: 10}, {key: 2, value: 20}, {key: 3, value: 30}]; let newArr = kvArray.map(item => { let obj = {} obj[item.key] = item.value return obj }) // newArr2 是 newArr 的简写形式 let newArr2 = kvArray.map(item=>({[item.key]:item.value})) console.log(newArr); //[Object { 1: 10 }, Object { 2: 20 }, Object { 3: 30 }] console.log(newArr2,'00');//[Object { 1: 10 }, Object { 2: 20 }, Object { 3: 30 }] "00"
- 取数组对象中的某一个特定参数
let j = kvArray.map(x=>x.value) console.log(j) //[10, 20, 30]
- 格式化字符串
let newStr = Array.prototype.map.call('new String', x => x + '*') console.log(newStr); //["n*", "e*", "w*", " *", "S*", "t*", "r*", "i*", "n*", "g*"] //number转字符串 var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]; arr.map(String); // ['1', '2', '3', '4', '5', '6', '7', '8', '9']
- 遍历dom取值
<select id="mapSelect"> <option value="map1">map1</option> <option value="map2" disabled>map2</option> <option value="map3" disabled>map3</option> </select> let select = document.querySelectorAll('option:disabled') let option = Array.prototype.map.call(select, x => x.value) console.log(option);//["map2", "map3"]
-
字符串转Number
通常情况下,map 方法中的 callback 函数只需要接受一个参数,就是正在被遍历的数组元素本身。但这并不意味着 map 只给 callback 传了一个参数。这个思维惯性可能会让我们犯一个很容易犯的错误。
let b = ["1", "2", "3"].map(parseInt); console.log(b) // [1, NaN, NaN]
通常使用parseInt时,只需要传递一个参数,但实际上,parseInt可以有两个参数.第二个参数是进制数, map方法在调用callback函数时,会给它传递三个参数:当前正在遍历的元素, 元素索引, 原数组本身。 第三个参数parseInt会忽视, 但第二个参数不会,也就是说: parseInt把传过来的索引值当成进制数来使用!从而返回了NaN!
所以我们可以改造一下该方法:
function returnInt(element) { return parseInt(element, 10); } ['1', '2', '3'].map(returnInt); // [1, 2, 3] // 也可以使用简单的箭头函数,结果同上 ['1', '2', '3'].map( str => parseInt(str) ); // 一个更简单的方式: ['1', '2', '3'].map(Number); // [1, 2, 3]
好了Map基本学习完了,接下来看一下reduce累加器
二、高阶函数——Reduce 累加器
-
Reduce函数是什么?
reduce() 方法接收一个函数作为累加器(accumulator),对数组中的每个元素(从左往右,升序执行)执行这个reducer函数,最后将其计算结果汇总并返回。 -
reduce 的写法与特征
let a = [1, 2, 3, 4] let b = a.reducer(function (accumulator,value, index, array) { return value + accumulator },initialValue) console.log(b);//10
reduce函数接收两个参数
- 必选——callback函数,返回累加器的最终计算结果,接收四个参数其中:
- accumulator(必选):上一次累加计算回调的返回值,首次计算取initialValue得值。
- value(必选):指正在处理的元素
- index(可选):指正在处理的元素的索引
- array(可选):指被处理的数组
- 可选——initialValue:作为第一次调用 callback函数时的第一个参数的值。 如果没有提供初始值,则将使用处理的数组中的第一个元素。 在没有初始值的空数组上调用 reduce 将报错。
为了更好的理解参数之间的关系,我们来看一个例子:
var arr = [1, 2, 3, 4, 5]; let d = null let b = arr.reduce(function (x, y,i) { let c = x+y console.log('x:'+i,x) console.log('y:'+i,y) console.log('c:'+i,c) return c }, d); console.log(b, 'b')
- 当传入参数为null 或 空 或 布尔值False 或数字 0 时,打印的值依次为:
let d = null / fasle / 0 > "x:0" null / fasle / 0 > "y:0" 1 > "c:0" 1 > "x:1" 1 > "y:1" 2 > "c:1" 3 > "x:2" 3 > "y:2" 3 > "c:2" 6 > "x:3" 6 > "y:3" 4 > "c:3" 10 > "x:4" 10 > "y:4" 5 > "c:4" 15 > 15 "b"
- 当传入参数为 Boolean (TRUE)时,打印值依次为 :
let d = true > "x:0" true > "y:0" 1 > "c:0" 2 > "x:1" 2 > "y:1" 2 > "c:1" 4 > "x:2" 4 > "y:2" 3 > "c:2" 7 > "x:3" 7 > "y:3" 4 > "c:3" 11 > "x:4" 11 > "y:4" 5 > "c:4" 16 > 16 "b"
- 当传入参数为undefined时,打印值依次为 :
let d = undefined > "x:0" undefined > "y:0" 1 > "c:0" NaN > "x:1" NaN > "y:1" 2 > "c:1" NaN > "x:2" NaN > "y:2" 3 > "c:2" NaN > "x:3" NaN > "y:3" 4 > "c:3" NaN > "x:4" NaN > "y:4" 5 > "c:4" NaN > NaN "b"
- 当传入参数为非0的number数字时,打印值依次为 :
let d = 10 > "x:0" 10 > "y:0" 1 > "c:0" 11 > "x:1" 11 > "y:1" 2 > "c:1" 13 > "x:2" 13 > "y:2" 3 > "c:2" 16 > "x:3" 16 > "y:3" 4 > "c:3" 20 > "x:4" 20 > "y:4" 5 > "c:4" 25 > 25 "b"
- 当传入参数为字符串时,打印值依次为 :
let d = 'aa' > "x:0" "aa" > "y:0" 1 > "c:0" "aa1" > "x:1" "aa1" > "y:1" 2 > "c:1" "aa12" > "x:2" "aa12" > "y:2" 3 > "c:2" "aa123" > "x:3" "aa123" > "y:3" 4 > "c:3" "aa1234" > "x:4" "aa1234" > "y:4" 5 > "c:4" "aa12345" > "aa12345" "b"
- 当传入参数为数组时,打印值依次为:
let d = ['a','b'] > "x:0" Array ["a", "b"] > "y:0" 1 > "c:0" "a,b1" > "x:1" "a,b1" > "y:1" 2 > "c:1" "a,b12" > "x:2" "a,b12" > "y:2" 3 > "c:2" "a,b123" > "x:3" "a,b123" > "y:3" 4 > "c:3" "a,b1234" > "x:4" "a,b1234" > "y:4" 5 > "c:4" "a,b12345" > "a,b12345" "b"
- 当不传参数时,打印值依次为
> "x:1" 1 > "y:1" 2 > "c:1" 3 > "x:2" 3 > "y:2" 3 > "c:2" 6 > "x:3" 6 > "y:3" 4 > "c:3" 10 > "x:4" 10 > "y:4" 5 > "c:4" 15 > 15 "b"
通过以上几个例子,我们可以看出来,在可选值 initialValue 传递参数的时候,可以得出几个特征:
- 不传递参数(例7),x 取得数组的第一项,y取得数组第二项,直接从索引为1开始计算。
- 传递参数,x 取得传入参数d的值,y取数组的第一项,从索引为0开始计算,累加结果为x和y之和。
- reduce返回的值b 是最后一次回调返回值(15)。
- 当传入布尔值为
true
时(例2),"x:0" true "y:0" 1 "c:0" 2
,在js运算中,会把 true 隐式转换为1, false隐身转换为0,所以累加器 c 的输出结果为 2。最终结果为16。
- 必选——callback函数,返回累加器的最终计算结果,接收四个参数其中:
下面我们看一下reduce日常的应用
-
reduce 的应用
- 计算数组或对象里值的和或各种运算
var initialValue = 0; var sum = [{x: 1}, {x:2}, {x:3}].reduce(function (accumulator, currentValue) { return accumulator + currentValue.x; },initialValue) var sum = [0, 1, 2, 3].reduce(function (accumulator, currentValue) { return accumulator + currentValue; }, initialValue); console.log(sum) // 6
- 将二维数组转化为一维
var flattened = [[0, 1], [2, 3], [4, 5]].reduce( function(a, b) { return a.concat(b); }, []); // flattened [0, 1, 2, 3, 4, 5]
- 将多维数组转化为以为数组
let arr = [[0, 1], [2, 3], [4,[5,6,7]]] const newArr = function(arr){ return arr.reduce((pre,cur)=>pre.concat(Array.isArray(cur)?newArr(cur):cur),[]) } console.log(newArr(arr)); //[0, 1, 2, 3, 4, 5, 6, 7]
- 数组排序去重
let arr = [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4]; let result = arr.sort().reduce((x,y)=>{ if(x.length == 0 || x[x.length-1] !== y) x.push(y) return x },[]) console.log(result);//[1, 2, 3, 4, 5]
- 计算字符串或者数组内部元素出现的次数
字符串 var arrString = 'abcaabc'; let result = arrString.split('').reduce((x, cur)=> { x[cur] ? x[cur]++ : x[cur] = 1 return x; }, {}) console.log(result);//{a: 3, b: 2, c: 2} 数组 var names = ['Alice', 'Bob', 'cc', 'cc', 'Alice'];; let result = names.reduce((x, cur)=> { x[cur] ? x[cur]++ : x[cur] = 1 return x; }, {}) console.log(result);//{Alice: 2, Bob: 1, cc: 2}
- 按顺序执行promise
function p1(a) { return new Promise((resolve, reject) => { resolve(a * 5); }); } function p2(a) { return new Promise((resolve, reject) => { resolve(a * 2); }); } function f3(a) { return a * 3; } function p4(a) { return new Promise((resolve, reject) => resolve(a * 4)); } let pall = [p1, p2, f3, p4] let e = pall.reduce((x, y) => { return x.then(y) }, Promise.resolve(10)) //输入10 ,经过p1变为50,p2变为100,f3变为300,p4变为1200 e.then(console.log)//1200
以上 关于reduce的学习就到这里了,下面学习一下Fileter
三、高阶函数——Fileter 过滤
-
Fileter 函数是什么?
fileter ()方法是一个数组的高阶函数,接受一个带有返回值的函数,使得数组的每一个元素都会调用这个指定的判断条件后,满足条件的元素的组成形成一个新数组,不改变原数组。 -
Fileter 的特征?
fileter函数和map函数的特征基本一致!很像很像,同样接收两个参数:- 必选——callback函数 ,函数内部函数 每个处理元素后的结果,最终组成一个新数组。接收三个参数其中:
- value(必选):指正在处理的元素
- index(可选):指正在处理的元素的索引
- array(可选):指被处理的数组
- 可选——thisArg:指的是函数内部this的指向。根据下面例子可以看出,如果没有传第二个参数时,map的内部this指向window,传了参数后this指向改变为所传的参数。
具体就不举例说明了,可参照map的例子自己验证一下,下面直接看如何应用:
- 必选——callback函数 ,函数内部函数 每个处理元素后的结果,最终组成一个新数组。接收三个参数其中:
-
Fileter 函数的应用
- 筛选数组中满足条件的元素
let filter = [2,322.4,,56,345,24,566,'123'].filter(item=>item>100) console.log(filter);// [322.4, 345, 566, "123"]
let filter = ['aads','bb','ccaa','ddbba'].filter(item=>item.includes('aa')) console.log(filter);// ["aads", "ccaa"]
- 选出数组对象中满足条件的对象
let filter = [{x:1},{x:34},{x:9}].filter(item=>item.x <10) console.log(filter);//Array [{ x: 1 },{ x: 9 }]
3.数组排序去重
let arr1 = [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4]; let result = arr1.sort().filter((x, y,self) => x !== self[y-1] ) console.log(result); //[1, 2, 3, 4, 5]
四、Array.from()
-
from函数是什么?
Array.from()可以将类数组和可迭代(Iterator)的对象转化为真实数组,但不改变初始值。- 部署了Iterator接口的对象,比如:Set,Map,Array,String。
- 类数组对象,就是一个对象必须有length属性,没有length,转出来的就是空数组。
-
from 的描述?
from 方法 接收三个参数:- 必选——arrayLike:想要转换成数组的伪数组对象或可迭代对象。
- 可选——map函数:每个项目调用该函数将返回的值将插入到新数组中。
- 可选——thisArg:指的是map函数内部this的指向。
const someNumbers = { '0': 10, '1': 15, length: 2 } //转化类数组 let arr = Array.from(someNumbers) //使用es6箭头函数最简写 let arr1 = Array.from(someNumbers, value => value * 2) //es6简写 let arr2 = Array.from(someNumbers).map((value) => { return value * 2 }) //方便理解版 let arr3 = Array.from(someNumbers, function (value) { return value * 2 }) console.log(arr) // =>[10, 15] console.log(arr1); // => [20, 30] console.log(arr2); // => [20, 30] console.log(arr3); // => [20, 30]
-
from函数的应用
- 将类数组转化为数组,比如上述的例子或者填充数据
let arr = Array.from({ length: 2 }, (x,i) => 'jack'+i) console.log(arr);//["jack0", "jack1"]
- 生成数字范围
function range(end) { return Array.from({ length: end }, (x, index) => index); } console.log( range(4));; // => [0, 1, 2, 3]
- 填充数组中布尔值为false的项如:undefined,null,0,fasle,空
let arr = [1,0,,,2,null,,3,false,4,'a',5,,] let arr1 = Array.from(arr, x => x||'无') console.log(arr);//[1, 0, undefined, undefined, 2, null, undefined, 3, false, 4, "a", 5, undefined] console.log(arr1);//[1, "无", "无", "无", 2, "无", "无", 3, "无", 4, "a", 5, "无"]
- 格式化字符串
let newStr = Array.from('new String', x => x + '*') console.log(newStr); //["n*", "e*", "w*", " *", "S*", "t*", "r*", "i*", "n*", "g*"] //number转字符串 let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]; let arr2 = Array.from(arr,x=>x.toString()) console.log(arr2);//["1", "2", "3", "4", "5", "6", "7", "8", "9"]
- 数组排序去重
let arr1 = [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4].sort(); let result = Array.from(new Set (arr1)) console.log(result); //[1, 2, 3, 4, 5]
由于from的第二个函数可以调用map函数,所以map可以做到的应用from都可以做到,并返回新数组。
结语
以上就是几个常用但是不太好用理解的高阶函数的学习过程,map和filter都是在处理数组方面很优秀,但是map在数据量很大的情况下性能方面次于foreach和for循环,所以根据情况使用,reduce累加的过程理解可能比较困难,多联系几个demo就可以了!!加油!!对了这几个都不兼容ie8急以下。。。放弃ie8了,我才不管他呢,哼
如果本文对你有帮助的话,请不要忘记给我点赞打call哦~o( ̄▽ ̄)do
有其他问题留言 over~
最后
以上就是贪玩御姐为你收集整理的js高阶函数——Map/ reduce /Fileter/From...的全部内容,希望文章能够帮你解决js高阶函数——Map/ reduce /Fileter/From...所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复