当前位置: 首页 > 科技观察

助你精通JS:函数式数组逻辑判断的7个高阶函数

时间:2023-03-14 23:38:32 科技观察

JavaScript是当今流行语言中对函数式编程支持最好的编程语言。我们继续构建函数式编程的基础。在上一篇文章中,我们分解介绍了四种转换数组的方法,分别是:array.reduce助你掌握JS:神奇的array.reduce方法10例array.map助你精通JS:神奇的数组6例.maparray.flat和array.flatMap助你精通JS:array.flat和flatMap使用指南为什么一门编程语言要花那么大的精力在数组的数据结构上呢?因为数组是我们日常思维的基石。比如你早起计划的一天的任务就是一个数组,你的购物清单就是一个数组。学习编程时,纸上的字符不能简单地看成是抽象的无意义的符号,要将它们还原到具体的生活和应用中。接下来,我们继续构建我们的思维。引入array.filter、array.find、array.findIndex和array.include(array.find用于特定情况)和array.indexOf(array.findInde用于特定情况)和array.some用于逻辑判断,array。every.1.1array.filter()概述filter()方法创建一个新数组,其中包含通过提供的函数完成的测试的所有元素。语法varnewArray=arr.filter(callback(element[,index[,array]])[,thisArg])参数callback该函数用于测试数组的每个元素。返回true意味着该元素通过测试并保留该元素,false则不会。它接受以下三个参数:-element当前正在处理的数组中的元素。-index可选正在处理的元素在数组中的索引。-array可选调用过滤器的数组本身。thisArg可选执行回调时为此使用的值。返回值通过测试的新元素数组,如果没有数组元素通过测试,则为空数组。1.2array.filter()说明filter为数组中的每个元素调用一次回调函数,并创建一个新数组,其中包含使回调返回true或等于true的值的所有元素。回调只会在已分配的索引上调用,而不会在那些已删除或从未分配过的索引上调用。未通过回调测试的元素将被跳过,并且不会包含在新数组中。调用回调时,传入三个参数:元素的值、元素的索引、遍历的数组本身。如果为过滤器提供了thisArg参数,它将在调用回调时用作this值。否则,回调的this值在非严格模式下为全局对象,在严格模式下为undefined。回调函数最终观察到的this值是根据普通函数看到的“this”的规则来确定的。filter不会改变原来的数组,它返回新的过滤后的数组。过滤器遍历的元素范围是在第一次调用回调之前确定的。调用filter后添加到数组中的元素不会被filter遍历。如果现有元素发生变化,则它们传递给回调的值是过滤器遍历它们时的值。不会遍历已删除或从未赋值的元素。案例01Filter排除所有较小的值下面的例子使用filter创建一个新数组,其元素由原数组中值大于10的元素组成。functionisBigEnough(element){returnelement>=10;}varfiltered=[12,5,8,130,44].filter(isBigEnough);//filteredis[12,130,44]case02过滤JSON中的无效条目下面的例子使用filter()创建具有非零ID的元素的json。vararr=[{id:15},{id:-1},{id:0},{id:3},{id:12.2},{},{id:null},{id:NaN},{id:'undefined'}];varinvalidEntries=0;functionisNumber(obj){returnobj!==undefined&&typeof(obj)==='number'&&!isNaN(obj);}functionfilterByID(item){if(isNumber(item.id)&&item.id!==0){returntrue;}invalidEntries++;returnfalse;}vararrByID=arr.filter(filterByID);console.log('FilteredArray\n',arrByID);//FilteredArray//[{id:15},{id:-1},{id:3},{id:12.2}]console.log('NumberofInvalidEntries=',invalidEntries);//NumberofInvalidEntries=5案例03在数组中查找下面的例子使用filter()根据搜索条件过滤数组的内容。varfruits=['apple','banana','grapes','mango','orange'];/***Arrayfiltersitemsbasedonsearchcriteria(query)*/functionfilterItems(query){returnfruits.filter(function(el){returnel.toLowerCase().indexOf(query.toLowerCase())>-1;})}console.log(filterItems('ap'));//['apple','grapes']console.log(filterItems('an'));//['banana','mango','orange']case04ES2015implementationconstfruits=['apple','banana','grapes','mango','orange'];/***Arrayfiltersitemsbasedonsearchcriteria(query)*/constfilterItems=(query)=>{returnfruits.filter((el)=>el.toLowerCase().indexOf(query.toLowerCase())>-1);}console.log(filterItems('ap'));//['apple','grapes']console.log(filterItems('an'));//['banana','mango','orang2.1array.find()概述find()方法返回数组中满足提供的测试函数的第一个元素的值。否则返回未定义。constarray1=[5,12,8,130,44];constfound=array1.find(element=>element>10);console.log(found);//expectedoutput:12另见3.1findIndex()方法,返回数组在中找到的元素的索引,而不是它的值。如果需要查找元素的位置或元素是否存在于数组中,请使用Array.prototype.indexOf()或Array.prototype.includes()。语法arr.find(callback[,thisArg])参数callback是对数组的每一项执行的函数,接收3个参数:element当前遍历的元素。index可选当前遍历的索引。array可选数组本身。thisArg可选执行回调时用作this的对象。返回满足提供的测试函数的值数组中第一个元素的值,否则返回未定义。2.2array.find()说明find方法对数组中的每个元素执行一个回调函数,直到一个回调函数返回true。当找到这样的元素时,该方法立即返回该元素的值,否则返回undefined。注意回调函数会被数组中从0到length-1的每一个索引调用,而不仅仅是那些赋值的,这意味着对于稀疏数组,这种方法的效率低于那些只遍历值索引的方法.回调函数有3个参数:当前元素的值、当前元素的索引和数组本身。如果提供了thisArg参数,那么每次回调函数执行时都会作为this使用,如果不提供,将使用undefined。find方法不会改变数组。元素的索引范围是在第一次调用回调函数时确定的,所以find方法开始执行后添加到数组中的新元素不会被回调函数访问。如果数组中一个没有被回调函数访问过的元素的值被回调函数改变了,那么当回调函数访问它时,它的值将是根据它在数组中的索引访问到的当前值。删除的元素仍将被访问,但其值已未定义。案例01利用对象的属性在数组中查找对象varinventory=[{name:'apples',quantity:2},{name:'bananas',quantity:0},{name:'cherries',quantity:5}];functionfindCherries(fruit){returnfruit.name==='cherries';}console.log(inventory.find(findCherries));//{name:'cherries',quantity:5}案例02下面数组中的素数这个例子展示了如何从一个数组中找到一个素数(如果没有找到素数则返回undefined)functionisPrime(element,index,array){varstart=2;while(start<=Math.sqrt(element)){if(element%start++<1){returnfalse;}}returnelement>1;}console.log([4,6,8,12].find(isPrime));//undefined,notfoundconsole.log([4,5,8,12].find(isPrime));//5在回调中删除数组中的一个值时,访问该位置时,传入的值未定义://Declararraywithnoelementatindex2,3and4vara=[0,1,,,,5,6];//显示所有索引,notjustthosethosethavebeenassignedvaluesa.find(function(value,index){console.log('Visitedindex'+index+'withvalue'+value);});//Showsallindexes,includingdeleteda.find(function(value,index){//Deleteelement5onfirstiterationif(index==0){console.log('Deletinga[5]withvalue'+a[5]);deletea[5];//注意:这里只是一个[5]设置为undefined,可以尝试用a.pop()删除最后一个item,还是会遍历到被删除的item}//Element5isstillvisitedeventhoughdeletedconsole.log('Visitedindex'+index+'withvalue'+value);});3.1array.findIndex()概述findIndex()方法返回数组中满足提供的测试函数的第一个元素的索引,如果没有找到对应的元素,则返回-1。varinventory=[{name:'apples',quantity:2},{name:'bananas',quantity:0},{name:'cherries',quantity:5}];functionfindCherries(水果){returnfruit.name==='cherries';}console.log(inventory.find(findCherries));//{name:'cherries',quantity:5}参见1.1find()方法,返回数组中找到的元素的值,而不是它的索引。语法arr.findIndex(callback[,thisArg])参数callback对于数组中的每个元素,都会执行回调函数,执行时会自动传入以下三个参数:-element当前元素。-index当前元素的索引。-array调用findIndex的数组。thisArg可选。执行回调时此对象的值。测试函数提供的返回值数组中第一个元素的索引。否则返回-13.2array.findIndex()说明findIndex方法对数组中每个数组索引0..length-1(含)执行回调函数,直到找到返回true值的回调函数(强制为true).如果找到这样的元素,findIndex会立即返回该元素的索引。如果回调从不返回真值,或者数组的长度为0,则findIndex返回-1。与Array#some等其他一些数组方法不同,在稀疏数组中,即使对于数组中不存在的条目的索引,也会调用回调函数。调用回调函数时带有三个参数:元素的值、元素的索引和要遍历的数组。如果为findIndex提供了thisArg参数,则每次调用回调函数时都会将其作为this使用。如果未提供,将使用未定义。findIndex不会修改调用它的数组。元素的索引范围是在第一次调用回调函数时确定的,所以在findIndex方法开始执行后新添加到数组中的元素不会被回调函数访问到。如果数组中一个没有被回调函数访问过的元素的值被回调函数改变了,那么当回调函数访问它时,它的值将是根据它在数组中的索引访问到的当前值。删除的元素仍然可以访问。案例01查找数组中第一个素数元素的索引下面的示例查找数组中第一个素数元素的索引(如果没有素数,则返回-1)。functionisPrime(元素、索引、数组){varstart=2;while(start<=Math.sqrt(element)){if(element%start++<1){returnfalse;}}returnelement>1;}console.log([4,6,8,12].find(isPrime));//undefined,notfoundconsole.log([4,5,8,12].find(isPrime));//2.1时54.1array.includes()概述当array.find找到特定元素时,它是array.include。includes()方法用于判断一个数组是否包含指定的值。根据情况,如果包含则返回true,否则返回false。语法arr.includes(valueToFind[,fromIndex])参数valueToFind需要查找元素值。注意:使用includes()比较字符串和字符是区分大小写的。fromIndex可选从中开始查找valueToFind的fromIndex索引。如果是负值,则从array.length+fromIndex的索引开始按升序查找(即使fromIndex的绝对值是从末尾向前跳转,再向后查找)。默认为0。返回值返回一个布尔值Boolean,如果在数组中找到则返回true(如果传入fromIndex,则表示在fromIndex指定的索引范围内找到)。Case00简单例子[1,2,3].includes(2);//true[1,2,3].includes(4);//false[1,2,3].includes(3,3);//false[1,2,3].includes(3,-1);//true[1,2,NaN].includes(NaN);//truecase01fromIndex大于等于长度如果fromIndex大于或等于数组的长度,则返回false并且不搜索数组。vararr=['a','b','c'];arr.includes('c',3);//falsearr.includes('c',100);//falsecase02计算的索引少小于0如果fromIndex为负数,则计算出的索引将用作开始搜索searchElement的位置。如果计算出的索引小于0,则搜索整个数组。//arraylengththis3//fromIndexis-100//computedindexis3+(-100)=-97vararr=['a','b','c'];arr.includes('a',-100);//truearr.includes('b',-100);//truearr.includes('c',-100);//truearr.includes('a',-2);//falsecase03作为一般方法includes()includes()方法被有意设计为通用方法。它不要求这个值是一个数组对象,所以它可以用于其他类型的对象(比如类数组对象)。以下示例显示了在函数的参数对象上调用的includes()方法。(function(){console.log([].includes.call(arguments,'a'));//trueconsole.log([].includes.call(arguments,'d'));//false})('a','b','c');5.1array.indexOf()概述indexOf()方法返回给定元素在数组中的第一个索引,如果不存在则返回-1。语法arr.indexOf(searchElement[,fromIndex])参数searchElement要搜索的元素fromIndex可选的搜索起始位置。如果索引值大于等于数组长度,则表示不查找数组,返回-1。如果参数中提供的索引值为负值,将作为数组末尾的偏移量,即-1表示从最后一个元素开始查找,-2表示从倒数第二个元素开始查找,等等。注意:如果参数中提供的索引值为负值,则不改变其查找顺序,查找顺序仍然是从前到后查询数组。如果偏移索引值仍然小于0,则查询整个数组。它的默认值为0。返回值是第一个找到的元素在数组中的索引位置;没有找到则返回-15.2array.indexOf()说明indexOf使用严格相等(无论是===,还是三等号运算符号都是基于同样的方法)来判断searchElement和其中包含的元素的关系阵列。Case01使用indexOf下面的例子使用indexOf方法来判断多个值在数组中的位置。vararray=[2,5,9];array.indexOf(2);//0array.indexOf(7);//-1array.indexOf(9,2);//2array.indexOf(2,-1);//-1array.indexOf(2,-3);//0案例02找出指定元素出现的所有位置varindices=[];vararray=['a','b','a','c','a','d'];varelement='a';varidx=array.indexOf(元素);while(idx!=-1){indices.push(idx);idx=array.indexOf(元素,idx+1);}console.log(indices);//[0,2,4]案例03判断一个元素是否在数组中,如果不在,则更新数组函数updateVegetablesCollection(veggies,veggie){if(veggies.indexOf(veggie)===-1){veggies.push(veggie);console.log('Newveggiescollectionis:'+veggies);}elseif(veggies.indexOf(veggie)>-1){console.log(veggie+'alreadyexistsintheveggiescollection.');}}varveggies=['potato','tomato','chillies','green-pepper'];//新蔬菜集合is:potato,tomato,chillies,green-papper,spinachupdateVegetablesCollection(veggies,'spinach');//spinachalreadyexistsintheveggiescollection.updateVegetablesCollection(veggies,'spinach');6.总结以上介绍了数组的5个函数,用于高级逻辑判断:array.filter、array.find、array、findIndex、array.includes、array.indexOf和比较常用但比较简单的array.every和array.some也用于逻辑判断,这里不再赘述