一篇文章让你理解for...in 和 for...of区别

1. for…in

1. 原理
for...in 是一种用于 遍历对象属性 的循环,它会枚举对象自身的和从原型链继承的 可枚举属性

  • **可枚举属性:**指 enumerable 属性为 true 的键,这些属性可以通过 Object.keys() 或 for…in 枚举出来。
  • **键名:**对于对象,键名始终是字符串;对于数组,键名是索引(以字符串形式返回)。

2. 使用场景
for...in 主要用于遍历对象的属性,而不适用于遍历数组尽管可以用它遍历数组,但由于数组的索引会被转为字符串形式,且可能遍历到原型链中的属性,因此会产生潜在问题。

- 适合遍历对象

const person = { name: "Alice", age: 25, job: "Engineer" };

for (let key in person) {
  console.log(key); // name, age, job
  console.log(person[key]); // Alice, 25, Engineer
}

- 不推荐用于数组

const arr = [1, 2, 3];

for (let index in arr) {
  console.log(index); // 输出:'0', '1', '2'(索引作为字符串)
  console.log(arr[index]); // 输出:1, 2, 3
}

- 为什么不推荐?

  1. 索引是字符串,而非数字。

  2. 如果数组有自定义属性,for…in 会将这些属性也枚举出来:

    const arr = [1, 2, 3];
    arr.custom = "hello";
    
    for (let key in arr) {
      console.log(key); // '0', '1', '2', 'custom'
    }
    

- for…in 的原型链问题
for…in 会遍历对象的 原型链,这可能带来意外结果:

const obj = { a: 1 };
Object.prototype.b = 2;

for (let key in obj) {
  console.log(key); // 输出:'a', 'b'
}

解决方法:使用 Object.hasOwnProperty() 检查是否为对象自身属性

for (let key in obj) {
  if (obj.hasOwnProperty(key)) {
    console.log(key); // 只输出:'a'
  }
}

- 高级用法
配合 Object.keys()、Object.values()、Object.entries()

  • Object.keys(obj):获取对象的所有 自身属性的键。
  • Object.values(obj):获取对象的所有 自身属性的值。
  • Object.entries(obj):获取对象的所有键值对,返回数组形式。
const obj = { a: 1, b: 2, c: 3 };

Object.keys(obj).forEach((key) => {
  console.log(key, obj[key]); // a 1, b 2, c 3
});

2. for…of

- 原理
for…of 是 ES6 引入的一种语法,用于遍历 可迭代对象(iterable)。一个对象是可迭代的,必须实现了 Symbol.iterator 接口。

  • 可迭代对象:包括数组、字符串、Map、Set、生成器等。
  • 返回值:直接返回每次迭代的值,而不是键名。

- 使用场景
for…of 适用于遍历 数组、字符串、Map、Set 等所有实现了迭代协议的对象。

  • 遍历数组

    const arr = [1, 2, 3];
    
    for (let value of arr) {
      console.log(value); // 1, 2, 3
    }
    
  • 遍历字符串

    const str = "hello";
    
    for (let char of str) {
      console.log(char); // h, e, l, l, o
    }
    
  • 遍历 Map

    const map = new Map([
      ["a", 1],
      ["b", 2],
    ]);
    
    for (let [key, value] of map) {
      console.log(key, value); // a 1, b 2
    }
    
  • 遍历 Set

    const set = new Set([1, 2, 3]);
    
    for (let value of set) {
      console.log(value); // 1, 2, 3
    }
    

- 高级用法

  • 与生成器函数配合
    生成器函数返回一个可迭代对象,可以直接用 for…of 遍历:

    function* generator() {
      yield 1;
      yield 2;
      yield 3;
    }
    
    for (let value of generator()) {
      console.log(value); // 1, 2, 3
    }
    
  • 与数组解构配合
    结合解构,可以简洁地获取数组元素:

    const arr = [[1, 2], [3, 4], [5, 6]];
    
    for (let [a, b] of arr) {
      console.log(a, b); // 1 2, 3 4, 5 6
    }
    

- 注意事项

  • for…of 无法直接遍历对象:

    const obj = { a: 1, b: 2 };
    
    // 报错:TypeError: obj is not iterable
    for (let value of obj) {
      console.log(value);
    }
    

    解决方法:使用 Object.entries() 将对象转换为可迭代的数组:

    for (let [key, value] of Object.entries(obj)) {
      console.log(key, value); // a 1, b 2
    }
    
  • 区分 for…of 和 for…in 的适用场景:

    • for…in 遍历对象的键名。
    • for…of 遍历可迭代对象的值。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值