大家好,我叫CUGGZ。JavaScript提供了很多循环遍历的方法。下面我们来详细了解一下这些方法的使用方法以及使用时的注意事项:一、数组遍历方法1.forEach()forEach方法用于调用数组的每个元素,并将元素传递给回调函数。为数组中的每个值调用回调函数。其语法如下:array.forEach(function(currentValue,index,arr),thisValue)该方法的第一个参数是回调函数,必须传入。它具有三个参数:currentValue:必需。当前元素索引:可选。当前元素的索引值。arr:可选。当前元素所属的数组对象letarr=[1,2,3,4,5]arr.forEach((item,index,arr)=>{console.log(index+":"+item)})这个方法还可以有第二个参数,用来绑定回调函数内部的this变量(前提是回调函数不能是箭头函数,因为箭头函数没有this):letarr=[1,2,3,4,5]letarr1=[9,8,7,6,5]arr.forEach(function(item,index,arr){console.log(this[index])//98765},arr1)注意:forEach方法不会改变原来的数组,也没有返回值;forEach不能使用break,continue跳出循环,使用return时,效果与for循环中使用continue相同;forEach方法不能遍历对象,只适用于数组遍历。2.map()map()方法会返回一个新的数组,数组中的元素是调用原数组元素的函数处理后的值。此方法按原始数组元素顺序依次处理元素。其语法如下:array.map(function(currentValue,index,arr),thisValue)该方法的第一个参数是回调函数,必须传入。它具有三个参数:currentValue:必需。当前元素的值;索引:可选。当前元素的索引值;arr:可选。当前元素所属的数组对象。让arr=[1,2,3];arr.map(item{returnitem+1;})//输出结果:[2,3,4]该方法的第二个参数用于绑定函数内部的参数这个变量是可选的:letarr=['a','b','c'];[1,2].map(function(e){returnthis[e];},arr)//输出结果:['b','c']这个方法也可以链式调用:letarr=[1,2,3];arr.map(itemitem+1).map(itemitem+1)//输出结果:[3,4,5]注意:map方法不会检测空数组;map方法在遍历数组时会返回一个新的数组,不会改变原数组;map方法有返回值,可以返回,在map回调函数中支持return返回值;map方法不能遍历对象,只适用于数组遍历。3.forof...of语句创建一个循环来迭代可迭代对象。ES6中引入的for...of循环替代了for...in和forEach(),并支持新的迭代协议。其语法如下:for(variableofiterable){statement}该方法有两个参数:variable:每次迭代的属性值赋值给这个变量。可迭代:具有可枚举属性并且可以迭代的对象。这个方法可以得到数组的每一项:letarr=[{id:1,value:'hello'},{id:2,value:'world'},{id:3,value:'JavaScript'}]for(letitemofarr){console.log(item);}//输出结果:{id:1,value:'hello'}{id:2,value:'world'}{id:3,value:'JavaScript'}注意:forof方法只会遍历属性当前对象的属性,而不是其原型链上的属性;forof方法适合遍历arrays/array-like/strings/map/set等带有迭代器对象的集合;forof方法不支持遍历普通对象,因为它没有迭代器对象。如果要遍历一个对象的属性,可以使用forin方法;可以使用break、continue、return来中断循环遍历;4.filter()filter()方法用于对数组进行过滤,返回满足条件的元素。它的参数是一个回调函数,对所有数组元素依次执行,返回结果为true的元素将被返回。如果没有符合条件的元素,将返回一个空数组。其语法如下:array.filter(function(currentValue,index,arr),thisValue)该方法的第一个参数是回调函数,必须传入。它具有三个参数:currentValue:必需。当前元素的值;索引:可选。当前元素的索引值;arr:可选。当前元素所属的数组对象。constarr=[1,2,3,4,5]arr.filter(itemitem>2)//输出结果:[3,4,5]同样,它还有第二个参数,用于绑定参数函数内部this变量。可以使用filter()方法去除数组中的undefined、null、NAN等值:letarr=[1,undefined,2,null,3,false,'',4,0]arr.filter(Boolean)//输出结果:[1,2,3,4]注意:filter方法会返回一个新数组,不会改变原数组;filter方法不会检测空数组;filter方法只适用于检测数组。5.some(),every()some()方法会遍历数组中的每一项,只要有一个元素满足条件就返回true,其余元素不测试,否则返回false.every()方法会遍历数组中的每一项,只有当所有元素都满足条件时才返回true。如果检测到数组中的某个元素不合格,则整个表达式返回false,其余元素不会再检测。其语法如下:两者的语法如下:array.some(function(currentValue,index,arr),thisValue)array.every(function(currentValue,index,arr),thisValue)的第一个参数两个方法是回调函数必须传递的,它有三个参数:currentValue:required。当前元素的值;索引:可选。当前元素的索引值;arr:可选。当前元素所属的数组对象。letarr=[1,2,3,4,5]arr.some(itemitem>4)//输出:trueletarr=[1,2,3,4,5]arr.every(itemitem>0)//输出结果:true注意:这两种方法都不会改变原来的数组,都会返回一个布尔值;两种方法都不会检测到空数组;这两种方法都只适用于检测阵列。6.reduce(),reduceRight()reduce()方法接收一个函数作为累加器,数组中的每个值(从左到右)最初被减少,最后被计算为一个值。reduce()可以用作函数compose的高阶函数。其语法如下:array.reduce(function(total,currentValue,currentIndex,arr),initialValue)reduce方法会依次对数组中的每个元素执行回调函数,不包括数组中已删除或从未分配过的元素,回调函数接受四个参数:total:上次回调调用返回的值,或者提供的初始值(initialValue);currentValue:当前正在处理的元素;currentIndex:当前元素的索引;arr:当前元素所属的数组对象。该方法的第二个参数是initialValue,表示传递给函数的初始值(作为第一次回调调用的第一个参数):letarr=[1,2,3,4]letsum=arr.reduce((prev,cur,index,arr)=>{console.log(prev,cur,index);returnprev+cur;})console.log(arr,sum);输出:121332643[1,2,3,4]10尝试添加一个初始值:letarr=[1,2,3,4]letsum=arr.reduce((prev,cur,index,arr)=>{console.log(prev,cur,index);returnprev+cur;},5)console.log(arr,sum);outputresult:5106218321143[1,2,3,4]15by由此可以得出结论:如果不提供初始值,reduce将从索引1开始执行回调方法,跳过第一个索引。如果提供初始值,reduceRight()方法从索引0开始执行,几乎与reduce()方法相同,只是此方法是倒序遍历数组,而reduce()方法是正向遍历。让arr=[1,2,3,4]让总和=arr。reduceRight((prev,cur,index,arr)=>{console.log(prev,cur,index);returnprev+cur;},5)console.log(arr,sum);输出:54393212211410[1,2,3,4]15注意:两种方法都不会改变原数组;如果这两个方法都加上初值,会改变原来的数组,初值放在数组的最后一位;这两个方法不会为空数组执行回调函数。7、find()、findIndex()find()方法返回函数判断出的数组第一个元素的值。当数组中的某个元素在条件测试时返回true时,find()返回满足条件的元素,之后的值不会再调用执行函数。如果没有匹配的元素,则返回undefined。findIndex()方法返回在满足条件的测试函数中传递的数组的第一个元素的位置(索引)。当数组中的元素满足函数条件时返回true,findIndex()返回满足条件的元素的索引位置,后面的值不会调用执行函数。如果没有匹配的元素,则返回-1。两个方法的语法如下:array.find(function(currentValue,index,arr),thisValue)array.findIndex(function(currentValue,index,arr),thisValue)两个方法的第一个参数是回调函数,这是必需的,它有三个参数:currentValue:必需的。当前元素;索引:可选。当前元素的索引;arr:可选。当前元素所属的数组对象。letarr=[1,2,3,4,5]arr.find(itemitem>2)//输出:3letarr=[1,2,3,4,5]arr.findIndex(itemitem>2)//输出结果:2find()和findIndex()几乎一样,只是返回结果不同:find():返回第一个满足条件的值;findIndex:返回第一个返回条件值的索引值。注意:这两个方法的功能对于空数组是不会执行的;这两种方法都不会改变原来的数组。8、keys()、values()、entries()这三个方法都返回一个数组的迭代对象,对象的内容不一样:keys()返回数组的索引值;values()返回数组的元素;entries()返回一个键值对数组。三个方法的语法如下:array.keys()array.values()array.entries()这三个方法没有参数:letarr=["Banana","Orange","Apple","Mango"];constiterator1=arr.keys();constiterator2=arr.values()constiterator3=arr.entries()for(letitemofiterator1){console.log(item);}//输出:0123for(letitemofiterator2){console.log(item);}//输出结果:香蕉橙苹果芒果for(letitemofiterator3){console.log(item);}//输出结果:[0,'Banana'][1,'Orange'][2,'Apple'][3,'Mango']总结:该方法是否改变了原数组的特征,forEach()无返回值,map()无返回值,可以链式forofnofor...of用Iterator迭代器遍历对象的属性,返回数组的元素和对象的属性值,不能遍历普通的obj对象,转异步循环进入同步循环filter()不过滤数组,返回一个con数组包含满足条件的元素,并且可以链接起来调用every()、some()或ifsome()只要其中之一为真就返回真;而every()只要其中一个为false.find()就返回false,findIndex()没有find()返回第一个满足条件的值;findIndex()返回第一个返回条件值的索引值reduce(),reduceRight()没有reduce()对数组的顺序操作;reduceRight()反转数组keys(),values(),entries()没有keys()返回数组的索引值;values()返回数组元素;entries()返回数组的键值对。二、对象遍历方法1.forinfor...in主要用于循环对象属性。每次执行循环中的代码时,都会对对象的属性执行一次操作。其语法如下:for(varinobject){executedcodeblock}两个参数:var:必需。指定的变量可以是数组元素或对象的属性。所需对象。指定要迭代的对象。varobj={a:1,b:2,c:3};for(variinobj){console.log('keyname:',i);console.log('键值:',obj[i]);}输出结果:键名:a键值:1键名:b键值:2键名:c键值:3注意:forin方法不仅会遍历当前对象的所有可枚举属性,其原型上的属性链条也被遍历。2.Object.keys(),Object.values(),Object.entries()三个方法用于遍历对象,返回给定对象自身的可枚举属性(不包括继承和Symbol属性),顺序数组元素的顺序与普通循环遍历对象时返回的顺序相同,这三个元素返回的值如下:Object.keys():返回包含对象键名的数组;Object.values():返回包含对象键的数组;Object.entries():返回包含对象键和键值的数组。letobj={id:1,name:'hello',age:18};console.log(Object.keys(obj));//输出结果:['id','name','age']console.log(Object.values(obj));//输出结果:[1,'hello',18]console.log(Object.entries(obj));//输出结果:[['id',1],['name','hello'],['age',18]注意Object.keys()方法返回的数组中的值为所有的字符串,也就是说不是字符串的键值都会被转换成字符串。结果数组中的属性值都是对象本身的可枚举属性,不包括继承的属性。3.Object.getOwnPropertyNames()Object.getOwnPropertyNames()方法类似于Object.keys()。它还接受一个对象作为参数,并返回一个包含对象本身所有属性名称的数组。但它可以返回不可枚举的属性。让a=['你好','世界'];目的。键(a)//["0","1"]对象。getOwnPropertyNames(a)//["0","1","length"]这两种方法都可以用来计算一个对象中属性的数量:varobj={0:"a",1:"b",2:"c"};Object.getOwnPropertyNames(obj)//["0","1","2"]Object.keys(obj).length//3Object.getOwnPropertyNames(obj).length//34.Object.getOwnPropertySymbols()Object.getOwnPropertySymbols()方法返回对象本身的Symbol属性不包含由字符串属性组成的数组:letobj={a:1}//给对象添加一个不可枚举的Symbol属性Object.defineProperties(obj,{[Symbol('baz')]:{value:'Symbolbaz',enumerable:false}})//给对象添加一个可枚举的Symbol属性obj[Symbol('foo')]='Symbolfoo'Object.getOwnPropertySymbols(obj).forEach((key)=>{console.log(obj[key])})//输出结果:SymbolbazSymbolfoo5.Reflect.ownKeys()Reflect.ownKeys()返回一个包含对象本身所有属性的数组。类似于Object.keys(),Object.keys()返回属性键,但不包括不可枚举的属性,而Reflect.ownKeys()返回所有属性键:varobj={a:1,b:2}Object.defineProperty(obj,'method',{value:function(){alert("Nonenumerableproperty")},enumerable:false})console.log(Object.keys(obj))//["a","b"]console.log(Reflect.ownKeys(obj))//["a","b","method"]注:Object.keys():相当于返回一个对象属性数组;Reflect.ownKeys():等价于Object.getOwnPropertyNames(obj).concat(Object.getOwnPropertySymbols(obj)yesnonoObjectWhether.getOwnPropertyNames()isObject.getOwnPropertySymbols()是No,Reflect.ownKeys()是Yes,它们分别是声明循环变量,判断循环条件,更新循环变量,这三个表达式用分号隔开。可以使用临时变量来缓存数组的长度,避免重复获取数组长度,当数组很大时,优化效果会更好显然constarr=[1,2,3,4,5]for(leti=0,len=arr.length;i
