js常用的循环遍历方式

61 阅读7分钟

这篇文章主要介绍了前端开发中 js 常用的循环遍历方式,包括 for 循环、forEach 循环、while 循环、map 循环、filter 循环等多种方式,对其特点、用法及注意事项进行了详细说明,我大概总结了一些比较常用的循环方式,总结的同时也巩固了一下基础知识。

for循环

for循环是最基本的,也是使用频率比较高的循环方式。能够满足绝大部分的遍历,可以遍历 数组、对象、字符串。可以使用break、return跳出循环,continue结束当前循环继续下个循环。

const arr = [1, 2, 3];
for(let i = 0; i < arr.length; i++) {
    console.log(arr[i]);
}
// 1,2,3

以上for循环可以优化,数组长度不变时可以将长度变量存起来,以优化性能。

const arr = [1, 2, 3];
for(let i = 0, len = arr.length; i < len; i++) {
    console.log(arr[i]);
}
// 1,2,3

forEach循环

forEach循环,break无法跳出循环,retrun只能跳出当前循环,无法终止循环。 forEach 是 for 的加升级版,使用更简单,携带参数更多,但本质还是数组的循环,每个元素都执行一次回调,不会改变原数组。

// 循环普通数组
const arr = [1, 2, 3]
arr.forEach(function (item, index, array) {
  // item数组中的当前项, index当前项的索引, array原始数组;
  console.log(item, index, array)
})

// 循环对象数组
const users = [
  { name: 'Alice', age: 25 },
  { name: 'Bob', age: 30 },
  { name: 'Charlie', age: 35 }
]
users.forEach(item => {
  console.log(`${item.name}今年${item.age}岁`)
})

while

当指定的条件为 true 时循环指定的代码块,所以使用while循环时,一定要注意,它必须要有退出条件,否则会成为死循环。

while 语句:先判断,再执行。

let num = 0
while (num < 10) {
	console.log(`num是:${num}`)
	num++
}

do...while

do...while 类似于while循环,不同之处在于先执行一次循环体代码,再执行指定表达式的运算。这意味着,do…while循环语句至少会执行一次循环体代码,即使条件为假。

do…while 语句:先执行,再判断。

let num = 0
do {
  console.log(`num是一个小于10的数字:${num}`)
  num++
} while (num < 10)

map

map方法返回一个新的数组,数组中的元素为原始数组调用函数处理后的值

注意:

  • map()方法不会对空数组进行检测
  • map()不会为数组中缺少的元素调用回调函数
  • map方法不会改变原始数组
// map()遍历数组的基本使用方式
let numbers = [1, 2, 3, 4]
let doubled = numbers.map(val => val * 2)
console.log(doubled) // 输出 [2,4,6.8]

filter

filter()方法用于过滤数组中的元素,并返回一个新数组。

注意:

  • filter() 不会对空数组进行检测;
  • filter() 不会改变原始数组。
let numbers = [1, 2, 3, 4]
let values = numbers.filter(val => val > 2)
console.log(values) // 输出 [3,4]

every

every通常和some一起用来比较。简单来说,some找到一个满足条件的就返回true,every必须全部都满足时才会返回true。

every() 方法是一个迭代方法。它会遍历数组的每一项,如果有有一项不满足条件,则表达式返回false,剩余的项将不会再执行检测;如果遍历完数组后,每一项都符合,则返回true。

  • every()对每一项都返回true,才返回true
  • 一旦找到不符合检测条件的元素就返回false,否则遍历全部元素。
// 遍历到第二项不满足条件,返回false并不再继续执行遍历了
const array1 = [12, 5, 8, 130, 44];
const result1 = array1.every((element, index, array)=> {
  return element >= 10;
}) 
console.log(result1) // false

// 每一项都大于10,所以返回true
const array2 = [12, 54, 18, 130, 44];
const result2 = array2.every((element, index, array)=> {
  return element >= 10;
}) 
console.log(result2) // true

some

some()方法也是是一个迭代方法。用于检测数组中的元素是否满足指定条件。如果有一个元素满足条件,则表达式返回true , 剩余的元素不会再执行检测。如果没有满足条件的元素,则返回false。

  • some找到一个满足条件的就返回true
  • 一旦找到符合条件的就返回true,否则遍历全部元素。
// 没有满足大于10的项,返回false
const array1 = [1, 3, 6, 8, 9]
const result1 = array1.some((element, index, array) => {
  return element >= 10
})
console.log(result1) // false

// 12满足大于10的条件,返回true
const array2 = [12, 1, 3, 6, 8]
const result2 = array2.some((element, index, array) => {
  return element >= 10
})
console.log(result2) // true

reduce

reduce() 方法对数组中的每个元素按序执行一个提供的 reducer 函数,每一次运行 reducer 会将先前元素的计算结果作为参数传入,最后将其结果汇总为单个返回值。

简单示例:数组求和

let arr = [1, 2, 3, 4, 5];
let result = arr.reduce((sum, current) => sum + current, 0);
console.log(result); // 15

find

find()是ES6引入的一种数组扩展方法,用于找出第一个符合条件的数组成员。 它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined。

简单示例:从对象数组中查找符合条件的对象。

const users = [
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' },
  { id: 3, name: 'John' }
]
const user = users.find((item, index, arr) => item.id === 2)
console.log(user) // 输出:{id: 2, name: 'Bob'}

注意:

  • find() 方法会遍历整个数组,直到找到满足条件的元素或者遍历完整个数组。
  • 当数组中的元素在测试条件时返回 true 时, find() 返回符合条件的元素,之后的值不会再调用执行函数。
  • 如果数组为空,那么返回 undefined。
  • 当多个元素符合条件时,find() 方法只会返回第一个符合条件的元素。
  • find()不会修改原始数组

findIndex

findIndex()方法的用法与find()方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。

简单示例:从对象数组中查找符合条件的第一个元素索引位置。

const users = [
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' },
  { id: 3, name: 'John' }
]
const index = users.findIndex((item, index, arr) => item.id === 2)
console.log(index) // 输出:1

注意:

  • 当数组中的元素在测试条件时返回 true 时, findIndex() 返回符合条件的元素的索引位置,之后的值不会再调用执行函数。
  • 如果没有符合条件的元素返回 -1
  • findIndex() 不会执行空数组。
  • findIndex() 不改变数组的原始值。

for...in

for...in循环:只遍历对象自身的和继承的可枚举的属性(包括原型链上的可枚举属性)。

const obj = { a: 1, b: 2, c: 3 }
for (let key in obj) {
  console.log(key) // a  b  c
}

注意:

  • for...in会返回继承的属性
  • for...in 循环并不是按照对象属性在对象中的顺序迭代的。
  • 由于 for...in 循环会遍历对象的原型链,因此可能会迭代到不是自身属性的属性。为了避免这种情况,我们可以使用 hasOwnProperty 方法来检查属性是否为对象自身的属性。

for...of

for...of主要用于遍历可迭代对象(例如数组、字符串、Set、Map等),可以获取到迭代对象的值。当使用 for...of 循环来遍历数组时,我们通常是为了遍历数组的元素,而不是索引。

const arr = [1, 2, 3];
for (const element of arr) {
  console.log(element);
}
// 1,2,3

注意

  • for...of:通常性能比 for...in 更好,因为它不需要遍历原型链上的属性。
  • 迭代的是对象的值本身,例如数组中的元素、字符串中的字符等。
  • for...of 循环不适用于迭代对象属性。

Object.keys

Object.keys()遍历对象,返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。

let person = {
  name: '张三',
  age: 20,
  gender: '女'
}
console.log(Object.keys(person)) //    ['name','age','gender']

Object.values

Object.values()遍历对象,返回一个数组,包含对象自身的所有可枚举属性值的 [ 数组 ] 。

let person = {
  name: '张三',
  age: 20,
  gender: '女'
}
console.log(Object.values(person)) //    ['张三',20,'女']

Object.getOwnPropertyNames()

Object.getOwnPropertyNames返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。

都可以遍历对象获取键名,那他们有什么不同点呢?

1. Object.getOwnPropertyNames(obj) 返回对象 obj 的所有属性(包括可枚举和不可枚举),而Object.keys(obj) 返回所有可枚举的属性。

const screen = {
  width: 1200,
  height: 800
}
Object.defineProperty(screen, 'resolution',{
  value: '1920 x 1080',
  enumerable: false //不可枚举
})

console.log(Object.getOwnPropertyNames(screen)) // ['width', 'height', 'resolution']
console.log(Object.keys(screen)) // ['width', 'height']

2. 对于数组,Object.getOwnPropertyNames()包含一个名为 length 的属性,Object.keys()没有。

const animals = ['dog', 'cat', 'tiger']
Object.keys(animals) // ['0', '1', '2']
Object.getOwnPropertyNames(animals) // ['0', '1', '2', 'length']

总结之后发现还有很多平时比较少用的循环遍历方式,前端技术更新不止,日新月异、知识的更新瞬息万变。只能说学无止境,步履不停。