js中的遍历

9 阅读6分钟

1. 字符串遍历

1. 高效和兼容性最佳

1.1. 使用 for 循环

const str = "hello"; 
for (let i = 0; i < str.length; i++) { 
    console.log(str[i]); 
}

优点

  • 高效:for 循环的性能通常很好。
  • 可控:可以灵活地控制循环的开始和结束,以及步进。

缺点

  • 代码较为冗长:相对于一些更简洁的方法,需要更多的代码。
  • 易错:容易出现索引错误。

1.2. 使用 String.prototype.charAt

const str = "hello";
for (let i = 0; i < str.length; i++) {
    console.log(str.charAt(i));
}

优点

  • 高效:与直接使用索引访问字符类似,性能较好。
  • 兼容性好:charAt 是老方法,兼容所有浏览器。

缺点

  • 冗长:与直接使用索引访问字符相比,代码略显冗长。

1.2简洁和可读性最佳

1.2.1. 使用 for...of 循环

const str = "hello";
for (const char of str) {
    console.log(char);
}

优点

  • 简洁:代码简洁明了。
  • 可读性好:更容易理解,特别是对于新手。
  • 支持 Unicode 字符:正确处理多字节字符。

缺点

  • 兼容性:需要 ES6 支持,对于旧版本的浏览器可能需要转译。

1.2.2. 使用 for...in 循环

const str = "hello";
for (const index in str) {
    console.log(str[index]);
}

优点

  • 简单:容易理解和使用。

缺点

  • 不推荐用于数组遍历:for...in 通常用于遍历对象的属性,不适用于数组遍历,因为它会遍历所有可枚举属性。
  • 性能较差:相对于 forfor...of 循环,性能可能较差。

1.3. 灵活性最佳

1.3.1. 使用 Array.fromforEach

const str = "hello";
Array.from(str).forEach(char => {
    console.log(char);
});

优点

  • 简洁:结合 forEach 使用,代码简洁。
  • 灵活:Array.from 可以将类数组对象或可迭代对象转换为数组。

缺点

  • 性能稍差:由于要先将字符串转换为数组,可能会影响性能。
  • 兼容性:需要 ES6 支持。

1.3.2. 使用扩展运算符和 forEach

const str = "hello";
[...str].forEach(char => {
    console.log(char);
});

优点

  • 简洁:结合 forEach 使用,代码简洁。
  • 灵活:扩展运算符可以将字符串转换为数组。

缺点

  • 性能稍差:由于要先将字符串转换为数组,可能会影响性能。
  • 兼容性:需要 ES6 支持。

1.3.3. 使用 String.prototype.splitforEach

const str = "hello";
str.split('').forEach(char => {
    console.log(char);
});

优点

  • 简洁:结合 forEach 使用,代码简洁。

缺点

  • 性能稍差:由于要先将字符串转换为数组,可能会影响性能。

2. 数组遍历

2.1 高效和可控

2.1.1 使用 for 循环

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

优点

  • 高效:for 循环的性能通常很好。
  • 可控:可以灵活地控制循环的开始、结束和步进。

缺点

  • 代码较为冗长:相对于一些更简洁的方法,需要更多的代码。
  • 易错:容易出现索引错误。

2.2 简洁和可读性好

2.2.1 使用 for...of 循环

const arr = [1, 2, 3, 4, 5];
for (const value of arr) {
    console.log(value);
}

优点

  • 简洁:代码简洁明了。
  • 可读性好:更容易理解,特别是对于新手。

缺点

  • 兼容性:需要 ES6 支持,对于旧版本的浏览器可能需要转译。

2.2.2 使用 forEach 方法

const arr = [1, 2, 3, 4, 5];
arr.forEach(value => {
    console.log(value);
});

优点

  • 简洁:代码简洁。
  • 可读性好:更容易理解,特别是对于新手。

缺点

  • 不可中断:forEach 循环不能使用 breakreturn 终止循环。
  • 兼容性:需要 ES5 支持,对于旧版本的浏览器可能需要转译。

2.3 创建新数组

2.3.1 使用 map 方法

const arr = [1, 2, 3, 4, 5];
const result = arr.map(value => value * 2);
console.log(result); // 输出 [2, 4, 6, 8, 10]

优点

  • 创建新数组:map 方法会创建一个新数组,数组中的每个元素是调用原数组中每个元素的回调函数的返回值。
  • 简洁:代码简洁。

缺点

  • 不用于仅遍历:map 方法主要用于转换数组,而不是仅仅遍历数组。

2.3.2 使用 filter 方法

const arr = [1, 2, 3, 4, 5];
const result = arr.filter(value => value > 2);
console.log(result); // 输出 [3, 4, 5]

优点

  • 创建新数组:filter 方法会创建一个新数组,数组中的每个元素是通过测试的所有元素。
  • 简洁:代码简洁。

缺点

  • 不用于仅遍历:filter 方法主要用于筛选数组,而不是仅仅遍历数组。

2.4 实现复杂逻辑

2.4.1 使用 reduce 方法

const arr = [1, 2, 3, 4, 5];
const sum = arr.reduce((accumulator, value) => accumulator + value, 0);
console.log(sum); // 输出 15

优点

  • 强大:reduce 方法可以用来实现许多复杂的操作,如累加、累乘等。
  • 简洁:代码简洁,适合实现复杂逻辑。

缺点

  • 初学者不易理解:对于新手来说,reduce 方法的用法可能比较难理解。

2.5 不推荐用于数组遍历

2.5.1 使用 for...in 循环

const arr = [1, 2, 3, 4, 5];
for (const index in arr) {
    console.log(arr[index]);
}

优点

  • 简单:容易理解和使用。

缺点

  • 不推荐用于数组遍历:for...in 通常用于遍历对象的属性,不适用于数组遍历,因为它会遍历所有可枚举属性,包括数组对象的自定义属性。
  • 性能较差:相对于 forfor...of 循环,性能可能较差。

3. 对象遍历

3.1 简单和兼容性好

3.1.1 使用 for...in 循环

//`for...in` 循环用于遍历对象的可枚举属性,包括继承的属性。
const obj = { a: 1, b: 2, c: 3 };
for (const key in obj) {
    if (obj.hasOwnProperty(key)) { // 检查是否为对象自身的属性
        console.log(`${key}: ${obj[key]}`);
    }
}

优点

  • 简单:容易理解和使用。
  • 广泛兼容:兼容所有浏览器。

缺点

  • 可能遍历继承的属性:需要使用 hasOwnProperty 过滤继承的属性。
  • 顺序不保证:遍历顺序不一定与属性添加顺序一致。

3.2 简洁、不遍历继承属性、顺序保证

3.2.1 使用 Object.keysforEach

//`Object.keys` 方法返回一个包含对象自身可枚举属性的数组,
//然后可以使用 `forEach` 遍历这些属性。
const obj = { a: 1, b: 2, c: 3 };
Object.keys(obj).forEach(key => {
    console.log(`${key}: ${obj[key]}`);
});

优点

  • 简洁:结合 forEach 使用,代码简洁。
  • 不遍历继承的属性:只遍历对象自身的属性。
  • 顺序保证:属性遍历顺序与添加顺序一致(在大多数情况下)。

缺点

  • 需要 ES5 支持:对于旧版本的浏览器可能需要转译。

3.2.2 使用 Object.valuesforEach

//`Object.values` 方法返回一个包含对象自身可枚举属性值的数组,
// 然后可以使用 `forEach` 遍历这些值。
const obj = { a: 1, b: 2, c: 3 };
Object.values(obj).forEach(value => {
    console.log(value);
});

优点

  • 简洁:结合 forEach 使用,代码简洁。
  • 不遍历继承的属性:只遍历对象自身的属性值。
  • 顺序保证:属性遍历顺序与添加顺序一致(在大多数情况下)。

缺点

  • 需要 ES8 支持:对于旧版本的浏览器可能需要转译。

3.2.3 使用 Object.entriesforEach

//`Object.entries` 方法返回一个包含对象自身可枚举属性键值对的数组,
// 然后可以使用 `forEach` 遍历这些键值对。
const obj = { a: 1, b: 2, c: 3 };
Object.entries(obj).forEach(([key, value]) => {
    console.log(`${key}: ${value}`);
});

优点

  • 简洁:结合 forEach 使用,代码简洁。
  • 不遍历继承的属性:只遍历对象自身的属性键值对。
  • 顺序保证:属性遍历顺序与添加顺序一致(在大多数情况下)。

缺点

  • 需要 ES8 支持:对于旧版本的浏览器可能需要转译。

3.2.4 使用 for...of 循环和 Object.entries

const obj = { a: 1, b: 2, c: 3 };
for (const [key, value] of Object.entries(obj)) {
    console.log(`${key}: ${value}`);
}

优点

  • 简洁:代码简洁明了。
  • 不遍历继承的属性:只遍历对象自身的属性键值对。
  • 顺序保证:属性遍历顺序与添加顺序一致(在大多数情况下)。

缺点

  • 需要 ES6 和 ES8 支持:对于旧版本的浏览器可能需要转译。