本文详细解析JavaScript中for...of与for...in遍历语句的核心区别。for...of基于ES6迭代器协议,适用于数组、字符串等可迭代对象,直接获取值;而for...in用于遍历对象键名。文章深入讲解Symbol.iterator接口与next方法机制,并提供处理普通对象遍历的多种方案。
首先介绍for...of循环。
for...of是ES6引入的新特性。其最直观的表现是:使用for...of遍历数组时,直接输出的是元素的值(value),这与for...in输出索引值(index)形成鲜明对比,这也是初学者最容易感知的差异。
其次,for of无法直接用于遍历普通的对象,它仅能遍历那些部署了iterator(迭代器)接口的类数组对象。
那么,究竟什么是iterator呢?
迭代器(Iterator)是一种提供统一访问机制的接口。任何数据结构只要部署了Iterator接口,即可通过遍历操作依次处理其所有成员。
以下示例展示了for...of无法直接遍历普通对象的情况:
let obj2 = { x: 1,y: 2, z: 3,};
for (const value of obj2) {
console.log(value);
}
//遍历时出错
//Uncaught TypeError: obj2 is not iterable原因在于普通对象并非可迭代对象。可迭代对象是指实现了迭代器协议的对象,该协议要求对象必须部署iterator方法,即挂载在原型上的Symbol(Symbol.iterator)方法。因此,使用for...of处理数组时,实际是调用了数组原型下的该方法。每次调用后,方法内部返回next方法,这相当于一个“指针”,下次调用时该“指针”向后移动。
对此,部分同学可能仍感到困惑,此处通过一个示例进行说明:
let obj = {
data: [1, 2, 3],
// 这里给对象实现了一个迭代器方法
[Symbol.iterator]() {
let index = 0;
const data = this.data;
return {
next() {
if (index < data.length) {
return { value: data[index++], done: false, };
} else {
return { done: true };
}
},
};
},
};
for (const value of obj) {
console.log(value);
}//1 2 3经过上述处理,我们便为对象实现了迭代器方法,从而可以使用for...of遍历该obj对象。这段代码可能令人费解,主要源于对Symbol.iterator和next方法的不熟悉,下面简要介绍这两个概念。
Symbol.iterator是一个函数属性,其返回值是一个迭代器对象。在对象中定义该属性后,当使用for of时,语言机制会寻找该方法,即next方法。在对象中使用此属性即覆盖了默认迭代器,从而实现自定义逻辑。- 其次我们要注意返回的迭代器对象:我们要知道,迭代器对象是要
带有next方法的对象,而且这个next方法的返回值还必须是一个包含value和done的对象。其中value是当前值,而done表示是否全部遍历完成. - 迭代器通常如何工作?无论是数组、对象、集合还是其他数据结构,迭代器中均提供了
next方法。每次调用next方法都会返回这个数据集合的下一个值。联想到C语言中“指针”的移动,这也就解释了为何需要next方法。 - 因此,这部分代码变得易于理解:我们实现了
Symbol.iterator方法,在内部定义索引index并获取data数组,随后return一个包含next方法的迭代器对象。若当前索引小于数组长度,则返回包含当前value值和done(false,表示迭代未完成)的对象;否则返回done为true的对象,表明迭代事件已完成。
经过上述处理,大家可以看到这种方式较为繁琐。若不想通过此方式获取每个值,只能采用其他巧妙手段:避免直接遍历对象,而是通过某种方法进行过渡处理。
因此,若使用for...of迭代对象,必须通过特定手段进行加工处理。
let sum = 0;
let obj3 = {x: 1,y: 2, z: 3,};
for (const value of Object.values(obj3)) {
sum += value;
}
console.log(Object.values(obj3));//[1,2,3]
console.log(sum);//6此处使用了Object.values方法获取对象中的值,处理后返回一个包含对象值的数组。像数组、Map、Set、字符串等内置迭代器的类型,均可使用for...of进行迭代处理。此外,还可使用Object.entries()和Object.keys()等方法处理,此处不再展开。
接下来介绍for...in循环。
在介绍完for...of后,紧接着说明for in。for in最直接的体现是它能直接遍历处理对象类型数据,无需像for...of那样增加迭代器属性。具体介绍如下:
let obj4 = {
hobby: "唱,跳,rap",
name: "kun",
sex: "男",
};
for (const key in obj4) {
console.log("属性名" + key, "属性值" + obj4[key]);
}采用这种方式不会报错,可正常打印输出值。因此,在实际场景中处理对象时通常使用for...in;而遇到字符串、Map等自带迭代器的类型,则交给for...of处理,具体场景具体分析。
这也印证了前文所述:使用for...in时打印的是key值,因此要获取属性值需通过obj4[key]。
同样,使用for...in也可处理Map、Set、String等类型数据。但与for...of最显著的区别在于,我们可以直接处理普通对象。
总结
本文解释了for...of为何不能处理普通对象及其处理方法,并介绍了每种方法适用的问题场景。因此,使用时需根据具体场景进行分析处理。
到此结束关于JavaScript中for...of和for...in区别详解的介绍。更多相关内容请搜索本站以往文章或继续浏览下方相关文章,希望大家以后多多支持本站!