JavaScript中的for...of和for...in循环容易遇到的问题及解决方法总结

 更新时间:2023年08月18日 10:52:06   作者:冷月半明  
在 JavaScript 编程中,for...of 和 for...in 是常用的循环语法,但它们在使用时可能会引发一些意想不到的问题,本文将分享我在使用这两种循环时所遇到的坑和经验,需要的朋友可以参考下

两者的区别:

  • 适用对象类型
    • for...of:主要用于遍历可迭代对象(例如数组、字符串、Set、Map等),可以获取到迭代对象的值。
    • for...in:主要用于遍历对象的属性(包括原型链上的属性),可以获取到属性名(键)。
  • 遍历顺序
    • for...of:按照对象的顺序迭代,一般用于遍历有序集合。
    • for...in:无法保证属性的遍历顺序,可能会导致属性的无序输出。
  • 迭代内容
    • for...of:迭代的是对象的值本身,例如数组中的元素、字符串中的字符等。
    • for...in:迭代的是对象的属性名,需要通过属性名访问属性值。
  • 支持情况
    • for...of:在 ES6 中引入,适用于可迭代对象,如数组、字符串等。
    • for...in:在早期版本的 JavaScript 中就存在,用于遍历对象的属性。但是不适用于数组等可迭代对象,因为它会遍历出额外的属性。
  • 性能
    • for...of:通常性能比 for...in 更好,因为它不需要遍历原型链上的属性。

示例代码演示两者的不同用法:

// for...of 遍历数组
const arr = [1, 2, 3, 4];
for (const element of arr) {
    console.log(element); // 输出数组的每个元素
}
// for...in 遍历对象的属性
const obj = { a: 1, b: 2, c: 3 };
for (const key in obj) {
    console.log(key);      // 输出属性名 a, b, c
    console.log(obj[key]); // 输出属性值 1, 2, 3
}
  // for...of 遍历数组
const arr = [1, 2, 3, 4];
for (const element of arr) {
    console.log(element); // 输出数组的每个元素
}
// for...in 遍历对象的属性
const obj = { a: 1, b: 2, c: 3 };
for (const key in obj) {
    console.log(key);      // 输出属性名 a, b, c
    console.log(obj[key]); // 输出属性值 1, 2, 3
}

总之,如果你想遍历数组或其他可迭代对象的值,使用 for...of;如果你想遍历对象的属性,使用 for...in

for...of 遍历数组的陷阱:

当使用 for...of 循环来遍历数组时,我们通常是为了遍历数组的元素,而不是索引。然而,在使用 for...of 循环时,有一些常见陷阱需要避免,特别是关于循环索引和遍历顺序的问题。下面是如何正确使用 for...of 循环来遍历数组,以及如何避免这些陷阱的解释:

1. 遍历元素而非索引: 使用 for...of 循环时,我们直接遍历数组的元素,而不需要关心索引的细节。这样可以使代码更加简洁易读。例如:

const array = [1, 2, 3, 4, 5];
for (const element of array) {
    console.log(element); // 输出数组的每个元素
}

2. 避免使用索引: 避免在 for...of 循环中使用额外的索引变量,因为 for...of 循环本身已经直接提供了数组的每个元素。这有助于减少代码复杂性和错误的机会。不推荐的写法:

const array = [1, 2, 3, 4, 5];
for (let i = 0; i < array.length; i++) {
    console.log(array[i]); // 避免这种额外使用索引的方式
}

3. 保持遍历顺序: for...of 循环保证按照数组中的顺序进行遍历,因此它适用于需要按顺序处理元素的场景。这确保了元素的处理顺序与它们在数组中的位置一致。

4. 不会遍历稀疏元素: for...of 循环不会遍历数组中的稀疏元素(未赋值的元素),只会遍历有实际值的元素。这有助于避免不必要的处理。

5. 适用于可迭代对象: 除了数组,for...of 循环还适用于其他可迭代对象,如字符串、Set、Map 等。这使得代码具有更广泛的适用性。

综上所述,使用 for...of 循环来遍历数组是一种更直观、简洁的方式,可以避免许多在传统 for 循环中容易犯的错误。通过专注于元素而非索引,保持遍历顺序,并充分利用循环的简洁性,我们可以提高代码的可读性和可维护性,减少错误的风险。

for...in 遍历对象的不可靠性:

在使用 for...in 循环时,可能会遇到一些问题,其中包括遍历顺序的不确定性和遍历到原型属性的风险。下面是对这些问题的探讨:

1. 遍历顺序的不确定性: for...in 循环无法保证遍历对象属性的顺序。这是因为对象属性在 ECMAScript 规范中被定义为无序的。因此,使用 for...in 循环来依赖属性遍历的特定顺序是不可靠的。

2. 遍历到原型属性的风险: for...in 循环会遍历对象自身属性以及继承自原型链的属性。这可能会导致意外的属性遍历,尤其是当我们只想遍历对象自身的属性时。

3. 原型属性被遍历:

function Person() {
    this.name = 'Alice';
}
Person.prototype.age = 30;
const person = new Person();
for (const prop in person) {
    console.log(prop); // 输出 'name' 和 'age'
}

/**
 * @param {Function} fn
 * @return {Array}
 */
array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
fn = function (n) {
    return String(n > 5);
}
Array.prototype.groupBy = function (fn) {
    const myMap = new Map();
    const keys = Object.keys(this);
    console.log(keys);
    for (const key in keys) {
        if (myMap.has(fn(this[key]))
        ) {
            myMap.set(fn(this[key]), myMap.get(fn(this[key])).concat([this[key]]));
        } else {
            myMap.set(fn(this[key]), [this[key]]);
        }
    }
    const myObj = {};
    for (const [key, value] of myMap) {
        myObj[key] = value;
    }
    return myObj;
};
array.groupBy(fn);
/**
 * [1,2,3].groupBy(String) // {"1":[1],"2":[2],"3":[3]}
 */

4. 使用 hasOwnProperty 过滤原型属性:

for (const prop in person) {
    if (person.hasOwnProperty(prop)) {
        console.log(prop); // 仅输出 'name'
    }
}

5. 遍历可枚举属性:

Object.defineProperty(person, 'country', {
    value: 'USA',
    enumerable: true
});
for (const prop in person) {
    console.log(prop); // 输出 'name'、'age' 和 'country'
}

6. 遍历不可枚举属性:

Object.defineProperty(person, 'address', {
    value: '123 Main St',
    enumerable: false
});
for (const prop in person) {
    console.log(prop); // 仅输出 'name' 和 'age'
}

7. 遍历顺序问题:

const obj = { a: 1, b: 2, c: 3 };
for (const prop in obj) {
    console.log(prop); // 输出 'a'、'b' 和 'c',但顺序不确定
}

8. 遍历字符串属性:

const str = 'Hello';
for (const char in str) {
    console.log(char); // 输出 '0'、'1'、'2'、'3' 和 '4'
}

综上所述,尽管 for...in 循环在某些情况下可以派上用场,但要特别小心遍历顺序的不确定性和遍历到原型属性的风险。在需要遍历对象属性时,推荐使用 Object.keysObject.valuesObject.entries 等方法,以获得更可靠的遍历结果。或者,考虑使用 for...of 循环来遍历数组和可迭代对象,以避免这些问题。

以上就是JavaScript中的for...of和for...in循环容易遇到的问题及解决方法总结的详细内容,更多关于JavaScript for...of和for...in循环的资料请关注脚本之家其它相关文章!

相关文章

  • javascript实现右侧弹出“分享到”窗口效果

    javascript实现右侧弹出“分享到”窗口效果

    这篇文章主要为大家介绍了javascript实现右侧弹出“分享到”窗口效果,以一个完整的js右侧弹出“分享到”窗口的实例代码进行分析,感兴趣的小伙伴们可以参考一下
    2016-02-02
  • 全面了解javascript中的错误处理机制

    全面了解javascript中的错误处理机制

    下面小编就为大家带来一篇全面了解javascript中的错误处理机制。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-07-07
  • 微信登录过程、openId、token详解(代码实现)

    微信登录过程、openId、token详解(代码实现)

    这篇文章主要介绍了微信登录过程、openId、token详解,本文通过示例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2024-08-08
  • Three.js实现3D机房效果

    Three.js实现3D机房效果

    这篇文章主要为大家详细介绍了Three.js实现3D机房效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-12-12
  • 小程序多文件上传 Tdesign的过程

    小程序多文件上传 Tdesign的过程

    众所周知,小程序文件上传还是有点麻烦的,其实主要还是小程序对的接口有诸多的不便,比如说,文件不能批量提交,只能一个个的提交,小程序的上传需要专门的接口,现在给大家分享小程序多文件上传 Tdesign的方法,感兴趣的朋友一起看看吧
    2023-11-11
  • JS实现字符串转日期并比较大小实例分析

    JS实现字符串转日期并比较大小实例分析

    这篇文章主要介绍了JS实现字符串转日期并比较大小的方法,以实例形式较为详细分析了JavaScript字符串与日期操作的技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-12-12
  • JavaScript中Promise的使用详解

    JavaScript中Promise的使用详解

    Promise,相信每一个前端工程师都或多或少地在项目中都是用过,毕竟它早已不是一个新名词。ES6中已经原生对它加以支持,在caniuse中搜索一下 Promise ,发现新版的chrome和firefox也已经支持。但是低版本的浏览器我们可以使用 es6-promise 这个 polyfill 库来加以兼容。
    2017-02-02
  • JavaScript setInterval()与setTimeout()计时器

    JavaScript setInterval()与setTimeout()计时器

    这篇文章主要介绍了JavaScript setInterval()与setTimeout()计时器,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • javascript 一段代码引发的思考

    javascript 一段代码引发的思考

    写在前面:这是一个关于Ext, Prototype, JavaScript方面的问题,其实下面遇到的问题本不是问题,都是因为错误的理解造成的,本文的宗旨是希望读者朋友避免我犯的同类错误,遇事三思而后行,同时也体会下发现问题,解决问题,反思问题这种精神活动所带来的快乐!
    2009-01-01
  • JS和canvas实现俄罗斯方块

    JS和canvas实现俄罗斯方块

    本文主要介绍了JS和canvas实现俄罗斯方块的实例。具有很好的参考价值。下面跟着小编一起来看下吧
    2017-03-03

最新评论