JS:各种遍历方式总结

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/caozp913/article/details/102511713

js的遍历方式真的是有很多,有用于遍历数组的,也有用于遍历对象的……各种方式有什么样的应用场景?如何选择恰当的遍历方式?很容易就让人迷糊,所以做一下总结吧。

第一种:普通for循环

// 直接遍历出的是索引,注意每次遍历都需要获取一次arr的长度。
for (j = 0; j < arr.length; j++) {
   
}

简要说明: 最简单的一种,也是使用频率最高的一种,虽然性能不弱,但仍有优化空间。

有索引就能方便地获取值。

支持continue和break。

第二种:优化版for循环

for (j = 0, len=arr.length; j < len; j++) {

}

简要说明: 使用临时变量,将长度缓存起来,避免重复获取数组长度,当数组较大时优化效果才会比较明显。

这种方法基本上是所有循环遍历方法中性能最高的一种。

第三种:forEach循环

arr.forEach(function(item, index){

});

简要说明: 数组自带的forEach循环,使用频率较高,实际上性能比普通for循环弱

可以直接获取索引和值。但是forEach不支持break和continue。可以支持return,js中return和continue的功能类似,可以退出当前方法,即相当于跳过本次循环???

第四种:forEach变种

Array.prototype.forEach.call(arr, function(item, index){

});

简要说明: 由于foreach是Array型自带的,对于一些非这种类型的,无法直接使用(如NodeList),所以才有了这个变种,使用这个变种可以让类似的数组拥有foreach功能。

实际性能要比普通foreach弱。

第五种:for…in循环

其实for…in循环是为了遍历对象的属性而设计的:​​​​

for ( 键名 in 被遍历的对象 ) {
	// 需要执行的代码
}

获取键名之后如何获取属性值呢?通过目标对象[键名],而不能使用点号.键名,否则会显示是undefined,因为此时遍历出的键名都是字符串类型的,不能直接点.来获取。

const person = {
    name: "cao",
    age: 20
};

for (let item in person) {
    console.log(person[item]);
}

for…in也能用来遍历数组,此时遍历出的键就是数组的索引值。如果数组具有可枚举的属性,也会被for…in遍历到,例如:

// for-in遍历数组
for(let i in arrTmp){
    console.log(i+": "+arrTmp[i])
}
//for-in会遍历到数组的属性
arrTmp.name="myTest";
for(let i in arrTmp){
    console.log(i+": "+arrTmp[i])
}
// 输出 0:value1  1:value2  2:value3  name:myTest

同理,也可以用来遍历字符串,遍历出来的是字符的索引值。

支持continue和break。

使用for…in遍历数组时可能会出现一些小问题,要注意一下

var arr=[1,2,3,4,5,6];
arr.value='val';
//在使用for in 遍历时
for(var i in arr){
    console.log(i+'   '+arr[i]);//这时的i为键值,不为数组索引
}
//输出
0   1
1   2
2   3
3   4
4   5
5   6
value   val
// 接着执行以下操作,这时出现问题:
 
arr;//输出[1, 2, 3, 4, 5, 6]
 
//使用 console.log(arr)时,这样
console.log(arr);//输出[1, 2, 3, 4, 5, 6, value: "val"]
 
//alert(arr)时
alert(arr);//输出[1, 2, 3, 4, 5, 6]

第六种:for…of遍历(需要ES6支持)

ES6中,新增了for-of遍历方法。它被设计用来遍历各种类数组集合,例如DOM NodeList对象、Map和Set对象,甚至字符串也行。官方的说法是:

for...of语句在可迭代对象(包括 Array, Map, Set, String, TypedArray,arguments 对象等等)上创建一个迭代循环,对每个不同属性的属性值,调用一个自定义的有执行语句的迭代挂钩

// for-of遍历数组,不带索引,i即为数组元素
for(let i of arrTmp){
    console.log(i)
}
//输出 "value1" "value2" "value3"
 
// for-of遍历Map对象
let iterable = new Map([["a", 1], ["b", 2], ["c", 3]]);
for (let [key, value] of iterable) {
  console.log(value);
}
//输出 1 2 3
 
// for-of遍历字符串
let iterable = "china中国";
for (let value of iterable) {
  console.log(value);
}
//输出 "c" "h" "i" "n" "a" "中" "国"

简要说明: 这种方式是es6里面用到的,性能要好于for…in,但仍然比不上普通for循环。

该种方式通常是直接获取显性的值,而无法直接获取索引。

支持continue和break。

第七种:Object.keys()方法

上面的方法,注重点都是数组的元素或者对象的属性值。如果单纯的想获取对象的所有属性名集合,js有原生的Object.keys()方法(低版本IE不兼容),返回一个由对象的可枚举属性名组成的数组:

/****Object.keys()返回键名数组****/
//数组类型
let arr = ["a", "b", "c"];
console.log(Object.keys(arr));
// (3) ['0', '1', '2']
 
// 类数组对象
let anObj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.keys(anObj));
// (3) ['2', '7', '100']
 
//一般对象
let xyz = {z: "zzz", x: "xxx", y: "yyy"};
console.log(Object.keys(xyz));
// (3) ["z", "x", "y"]

javascript原生遍历方法的建议用法:

  • 如果要遍历数组,使用普通for循环或者forEach循环即可,虽然前者的效率较高,但是后者貌似因为更优雅且不易在索引上出错而被用得更多,并且forEach能直接获取数据和对应索引,只是forEach不支持continue和break,而普通for循环支持。
  • 如果要遍历对象,使用for…in即可,可直接遍历出键,再根据键来获取值。
  • 用for-of来遍历类数组对象(ES6),如果要遍历字符串,也可以用for…of。
  • 如果只是需要对象的键集合,使用Object.keys()即可。

有返回值的遍历方式

以上都是没有返回值的遍历,也就是单纯地遍历。如果想要在遍历之后返回一些值,有哪些方法可以用呢?

有以下七种:map、reduce、filter、find、findIndex、some、every,这些方法在格式上都是类似的,只是功能不同,虽然有些也可以作为单纯遍历使用而不去返回任何值,但是貌似没有太大的必要。

map

表示一一映射,数组有多少个数据,就映射出多少个数据,会返回一个新的数组。比如:

const arr = [81, 52, 73, 44];

const arr2 = arr.map(item => {
    return item > 60 ? `及格` : `不及格`;
});
//返回的arr2 = [`及格`, `不及格`, `及格`, `不及格`];

map方法传递一个回调函数作为参数,该回调函数可以接收两个参数,依次获取目标数组中的每一个数据和对应的索引,上例中没有用到index,故没有给出。

reduce

不管进去多少个,都只出来一个,该方法也需要传递一个回调函数,回调函数可以接收三个参数:temp、item、index,分别表示临时的中间数据、遍历出的每一个数据、索引。比如获取数组中所有值的和:

const arr = [1, 2, 3, 4, 5];

arr.reduce(function(temp, item, index){
    return temp + item; // 会返回所有值的和
});

以上的temp和item到底怎么理解呢?第一次循环temp和item分别为1和2,第二次分别为3和3,第三次分别为6和4,接着10和5,然后返回10+5,就是所有值的和,也就是说,temp存储的是前面依次相加的临时值。

filter

filter方法用于过滤某些数据,并不直接返回值,而是返回布尔值,返回true表示保留数据,否则不保留。比如返回偶数数组:

const arr = [81, 52, 73, 44];

const arr2 = arr.filter(item => item % 2 == 0);
//返回的arr2 = [52, 44];

 find

find方法和filter方法的返回方式类似,也是返回布尔值,如果是true就返回对应的值,但是find方法只要一找到符合条件的值就会马上退出遍历,最终只会返回一个值,如果没有找到满足条件的值,就会返回undefined。这个可以用于找到满足条件的数据就需要break循环的场景中。

const arr = [15, 19, 17, 13];
const value = arr.find(item => item % 2 === 1);
console.log(value); // 15

findIndex

findIndex的用法和find一模一样,只不过返回的是满足条件数据对应的索引,如果找不到,就返回-1。

const arr = [15, 19, 17, 13];
const value = arr.findIndex(item => item % 2 === 0);
console.log(value); // -1

some

该方法返回的是一个布尔值,用于判断数据中是否存在满足条件的数据,如果存在,则返回true,只要遇到第一个就会返回,后面的不再判断。

const arr = [15, 19, 17, 13];
const isExist = arr.some(item => item % 2 === 0);
console.log(isExist); // false

every

该方法用于判断是否每一个数据都满足条件,只要全都满足才返回true,只要有一个不满足就返回false,并且停止遍历。

const arr = [15, 19, 17, 13];
const isExist = arr.some(item => item % 2 === 1);
console.log(isExist); // true

猜你喜欢

转载自blog.csdn.net/caozp913/article/details/102511713