likes
comments
collection
share

哪些 for in 和 for of 以及遍历迭代踩过的坑

作者站长头像
站长
· 阅读数 53

前言

起因是这样的,面试官先问我讲讲Set这种数据结构,我框框讲完后面试官又问有哪些方法可以遍历它,我脑海中有forEach方法可以遍历,但是我知道面试官最想听到的肯定不是这个答案,因为这也太小儿科了,但是问题来了,我本人也忘了Set这种数据结构有没有 迭代器(Iterator) 这种属性,到底是用 for in 还是用 for of 遍历,面完了后突然想到迭代器和Set都是es6新出的内容,怎么可能会没有,看来真的是简单问题里面看细节,输的很彻底,还是需要对自我不断拷打......

1. Set

Set 是一种集合数据结构,用于存储唯一值,即每个值在 Set 中只出现一次,常用于数组去重操作:

哪些 for in 和 for of 以及遍历迭代踩过的坑

可以看到 Set 中的值是唯一的,不允许重复值,给数组去重的 Set 对象的每个值其实也像对象一样是一种键值对的形式,因为在 Set 中值本身就是唯一的键。与普通对象(Object)不同,Set 中的值没有对应的键名,只有值本身。

除此之外,Set 常见方法还有add、has、size、delete、cleaer等:

// 创建一个空的 Set 实例
const mySet = new Set();

// 向 Set 中添加值
mySet.add(1);
mySet.add(2);
mySet.add(3);
mySet.add(2); // 试图添加重复的值,但由于 Set 中值是唯一的,所以这个操作不会改变 Set 的内容

// 判断 Set 中是否包含某个值
console.log(mySet.has(2)); // 输出: true
console.log(mySet.has(4)); // 输出: false

// 返回 Set 中值的数量
console.log(mySet.size); // 输出: 3

// 从 Set 中删除一个值
mySet.delete(2);

// 再次判断 Set 中是否包含某个值
console.log(mySet.has(2)); // 输出: false

// 清空 Set 中的所有值
mySet.clear();
console.log(mySet.size); // 输出: 0

使用 add 方法向其中添加值,使用 has 方法判断是否包含某个值,使用 size 属性获取值的数量,使用 delete 方法删除值,使用 clear 方法清空 Set 中的所有值。

2. for in

for...in 是一种用于遍历对象的属性的语句。它可以遍历对象自身的可枚举属性以及继承的可枚举属性(来自原型链)。一般情况下,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 遍历数组

const obj = [1,2,3]; 
for (let key in obj) { 
    console.log(key); // 输出 0 1 2
}

注意

在第一个例子中由于 for...in 会遍历对象的原型链,因此在使用时需要注意可能会遍历到继承的属性,或者通过 hasOwnProperty 方法进行判断。

在第二个例子中for...in 循环遍历了数组 obj 的索引,因为数组也是一种特殊的对象,其索引会被视为属性名。所以,for...in 循环输出的是数组的索引(即属性名),而不是数组元素的值。

3. for of

当需要遍历一个集合(如数组、字符串、Map、Set 等)的元素时,可以使用 for...of 循环。for...of 可以简洁而直观的方式来遍历集合中的每个元素,无需关心索引等底层细节。 一个对象如果要具备可被for...of循环调用就必须在Symbol.iterator属性上有可调用的 Iterator 接口

使用 for...of 遍历普通对象

哪些 for in 和 for of 以及遍历迭代踩过的坑

使用 for...of 遍历数组

哪些 for in 和 for of 以及遍历迭代踩过的坑

第一个例子可以看到普通对象是没有可迭代属性Symbol.iterator所以会报错。

第二个例子中,for...of 循环只能用于可迭代对象(具有 Symbol.iterator 属性的对象),数组是具有迭代器属性可以被循环迭代,所以对于普通对象,仍然需要使用 for...in 循环或其他方式来进行遍历。

哪些 for in 和 for of 以及遍历迭代踩过的坑

4. 迭代器

官网对于迭代器是这么介绍的:

哪些 for in 和 for of 以及遍历迭代踩过的坑

也就是说,一个数据结构只要部署了Symbol.iterator属性,就被视为具有 iterator 接口,就可以用for...of循环遍历它的成员。for...of循环内部调用的是数据结构的Symbol.iterator方法。

原生具备 Iterator 接口的数据结构如下。

  • Array
  • Map
  • Set
  • String
  • TypedArray
  • 函数的 arguments 对象
  • NodeList 对象

5. 回归正题:哪些方法可以遍历Set?

  1. 使用forEach方法
const mySet = new Set([1, 2, 3, 4, 5]);

mySet.forEach(element => {
    console.log(element);
}); // 输出1 2 3 4 5
  1. 使用for...of循环
const mySet = new Set([1, 2, 3, 4, 5]);

for (const element of mySet) {
    console.log(element);
} // 输出1 2 3 4 5
  1. 转换为数组后遍历
const mySet = new Set([1, 2, 3, 4, 5]);
const myArray = Array.from(mySet);
// for of 遍历
for (const element of myArray) {
    console.log(element);
} 

//  map 遍历
const mySet = new Set([1, 2, 3, 4, 5]);
const myArray = Array.from(mySet).map(element => { console.log(element)});

自我总结

别再傻傻地分不清for...infor...of 啦,for...ofSetMap都是es6新出的,需要具有迭代器属性才能用for...of进行遍历,此外StringArray也是具有迭代属性可以被for...of进行遍历,普通对象没有迭代属性会报错.

for...in可以专门用来遍历对象,它可以遍历可枚举属性,去得到对象的键,而数组没有对象所谓的键所以会默认用下标来当成键遍历, 遍历数组会输出下标值。

分不清可以这样想,我们平时写项目的时候遍历一个对象不都是 v-for:"item in data" 吗,这就是for...in的遍历,剩下的数组呀,Set、Map 啦不就是给剩下的for...of遍历啦。

转载自:https://juejin.cn/post/7350502488493490210
评论
请登录