JS中for...in?和?for...of?的区别解析

 更新时间:2024年03月27日 14:34:55   作者:fighting?~  
for?…?in?用于迭代对象的可枚举字符串属性,包括自身属性和继承的属性,但不会遍历对象的原型链上的?非可枚举属性,以及对象的方法,这篇文章主要介绍了JS中for...in?和?for...of?的区别,需要的朋友可以参考下
(福利推荐:【腾讯云】服务器最新限时优惠活动,云服务器1核2G仅99元/年、2核4G仅768元/3年,立即抢购>>>:9i0i.cn/qcloud

(福利推荐:你还在原价购买阿里云服务器?现在阿里云0.8折限时抢购活动来啦!4核8G企业云服务器仅2998元/3年,立即抢购>>>:9i0i.cn/aliyun

1. 迭代的对象不同

  • for … in 用于迭代对象的可枚举字符串属性,包括自身属性继承的属性,但不会遍历对象的原型链上的 非可枚举属性,以及对象的方法。

从内置构造函数(如 Array 和 Object)创建的对象会从 Array.prototype 和 Object.prototype 继承不可枚举属性,例如 Array 的 indexOf() 方法或 Object 的 toString() 方法,它们在 for…in 循环中不会被访问到。

  • for … of 用于迭代可迭代对象定义的要进行迭代的值。可迭代对象 包括 数组、字符串、Set、Map等,还包括 arguments 对象。它遍历的是可迭代对象的迭代器(Iterator)返回的值或键值对,而不能直接用于普通的对象。

当 for…of 循环迭代一个可迭代对象时,它首先调用可迭代对象的 @@iterator 方法,该方法返回一个迭代器,然后重复调用生成器的 next() 方法,以生成要分配给 每次循环迭代的 可迭代对象 的值的序列。

注意: 每次迭代都会创建一个新的变量。在循环体内部重新赋值变量不会影响可迭代对象的原始值。

要成为可迭代对象,必须要有一个迭代器 @@iterator方法,也就是说这个对象必须有一个键为@@iterator的属性,通过常量 Symbol.iterator 访问这个属性,并返回一个迭代器对象

迭代器对象包含一个 next() 方法,无参数或者接受一个参数的函数,并返回符合 IteratorResult 接口的对象。
next() 方法会返回一个具有 valuedone 属性的对象。

  • value 表示当前迭代的值。如果迭代器已经到达末尾,那么 value 的值通常为 undefined,但这并不是必然的,具体取决于迭代器的实现。
  • done 是一个布尔值,表示迭代是否已完成。迭代器是否已完成遍历。当遍历结束时,done 为 true,否则为 false。

实际上,两者都不是严格要求的;如果返回没有任何属性的对象,则实际上等价于 { done: false, value: undefined }

const obj = {
  a: 1,
  b: { h:123 },
};
//定义在自身的属性
Object.defineProperty(obj, 'c', {
  value: 3,
});
//定义在自身的属性
Object.defineProperty(obj, 'd', {
  value: 4,
  enumerable: true,//是否可枚举,默认false不可枚举
});
//定义在原型上的属性
Object.prototype.e=5;
for (let key in obj) {
  console.log(key); // 输出 'a' 、 'b'、 'd'、'e',但不会输出 'c'、'h'
}
console.log(Object.keys(obj)); // 输出 ['a', 'b','d'],不包括 'c'、'e'、'h'
console.log(Object.getOwnPropertyNames(obj)); // 输出 ['a', 'b', 'c','d'],包括 'c', 但不包括'e'、'h'
扩展:

Object.keys 会返回一个包含所有可枚举自有字符串属性的数组,
Object.getOwnPropertyNames 则会包含所有属性,包括不可枚举的。
Object.getOwnPropertyDescriptor(obj, prop)静态方法返回一个对象,该对象描述给定对象上特定属性(即直接存在于对象上而不在对象的原型链中的属性)的配置。

obj
要查找其属性的对象。
prop
要检索其描述的属性的名称或 Symbol。
返回值
如果指定的属性存在于对象上,则返回其属性描述符,否则返回 undefined。
// 对象本身的属性的属性描述符
const desc = Object.getOwnPropertyDescriptor(obj, "c");
console.log(desc);
// {
//	value: 3, 
// 	writable: false,
//	enumerable: false, 
// 	configurable: false
// }
// 对象原型上的属性的属性描述符
const desc1 = Object.getOwnPropertyDescriptor(Object.prototype, "e");
console.log(desc1);
//{
//	value: 5, 
//	writable: true, 
//	enumerable: true, 
//	configurable: true
// }

属性描述符

  • value
与属性关联的值(仅限数据描述符)。
  • writable :是否可更改
当且仅当与属性关联的值可以更改时,为 true(仅限数据描述符)。
  • enumerable : 是否可枚举
当且仅当此属性在相应对象的属性枚举中出现时,为 true。
  • configurable :是否可删除
当且仅当此属性描述符的类型可以更改且该属性可以从相应对象中删除时,为 true。

在迭代 Array 时,for…of 循环和 for…in 循环之间的区别。

Object.prototype.objCustom = function () {};
Array.prototype.arrCustom = function () {};
const iterable = [3, 5, 7];
iterable.foo = "hello";
for (const i in iterable) {
  console.log(i);
}
// "0"、"1"、"2"、"foo"、"arrCustom"、"objCustom"
for (const i in iterable) {
  if (Object.hasOwn(iterable, i)) {
    console.log(i);
  }
}
// "0" "1" "2" "foo"
for (const i of iterable) {
  console.log(i);
}
// 3 5 7

使用 Object.hasOwn() 来检查找到的可枚举属性是否为对象的自有属性,即非继承属性。

const arr=['A','B', ,'D', ,'F'];
  for(const key in arr){
    console.log(key); //0,1,3,5
  }
  for(const item of arr){
    console.log(item); // A,B,undefined,D,undefined,F
  }

for…in 使用属性枚举而不是数组的迭代器。在稀疏数组中,for…of 会访问空槽,但 for…in 不会访问空槽。

2. 遍历顺序

  • for … in 循环遍历对象属性时,遍历的顺序是不确定的,因为对象属性没有固定的顺序。

根据现代 ECMAScript 规范的定义,遍历的顺序是一致且可预测的。在原型链的每个组件中,所有非负整数键(可以作为数组索引)将首先按值升序遍历,然后是其他字符串键按属性创建的先后顺序升序遍历。

  • for … of 循环遍历可迭代对象时,遍历的顺序是按照对象的迭代器定义的顺序进行的。

3. 可迭代性要求

  • for … in 循环不需要对象满足可迭代性要求。
  • for … of 循环要求被遍历的对象必须是可迭代对象(实现了迭代器接口)。如果对象没有迭代器接口,尝试使用 for … of 循环会抛出错误。

总的来说:

  • for…in 循环用于迭代对象的可枚举字符串属性,包括自身属性继承的属性
  • for…of 循环用于迭代可迭代对象定义的要进行迭代的值

到此这篇关于JS中for...in 和 for...of 的区别的文章就介绍到这了,更多相关js for...in 和 for...of 区别内容请搜索程序员之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持程序员之家!

相关文章

  • from 表单提交返回值用post或者是get方法实现

    from 表单提交返回值用post或者是get方法实现

    from 表单提交的返回值可以用jquery的post或者是get方法去实现,具体如下,感兴趣的朋友可以参考下,希望对大家有所帮助
    2013-08-08
  • 在javascript中如何得到中英文混合字符串的长度

    在javascript中如何得到中英文混合字符串的长度

    本文为大家介绍下Javascript中如何得到中英文混合字符串的长度,下面有个不错的教程,感兴趣的朋友可以参考下
    2014-01-01
  • JavaScript数据结构之优先队列与循环队列实例详解

    JavaScript数据结构之优先队列与循环队列实例详解

    这篇文章主要介绍了JavaScript数据结构之优先队列与循环队列,结合实例形式较为详细的分析了javascrip数据结构中优先队列与循环队列的原理、定义与使用方法,需要的朋友可以参考下
    2017-10-10
  • javaScript(JS)替换节点实现思路介绍

    javaScript(JS)替换节点实现思路介绍

    获取要替换的节点,这种方法只适用于IE浏览器以及适用于各种浏览器的写法,感兴趣的朋友可以参考下哈
    2013-04-04
  • 网站基于flash实现的Banner图切换效果代码

    网站基于flash实现的Banner图切换效果代码

    这篇文章主要介绍了网站基于flash实现的Banner图切换效果代码,是基于Flash与js实现的banner图片自动定时切换特效,并附有完整的示例源码,非常具有实用价值,需要的朋友可以参考下
    2014-10-10
  • 详解tween.js的使用教程

    详解tween.js的使用教程

    本篇文章主要介绍了详解tween.js的使用方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09
  • Javascript中级语法快速入手

    Javascript中级语法快速入手

    本文是一篇关于Javascript的中级进阶总结。小编希望大家能够在30分钟之内阅读完并认真体会,多敲代码,多总结,毕竟Javascript本身并不难。
    2016-07-07
  • 如何用js获得当前视频播放的状态

    如何用js获得当前视频播放的状态

    这篇文章主要给大家介绍了关于如何用js获得当前视频播放状态的相关资料,大家在日常应用场景中可能会遇到这么一个情况,需要判断用户是否完整的观看完了一部视频,需要的朋友可以参考下
    2023-07-07
  • Axios+Spring?Boot实现文件上传和下载

    Axios+Spring?Boot实现文件上传和下载

    这篇文章主要为大家详细介绍了Axios+Spring?Boot实现文件上传和下载,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-08-08
  • js记录点击某个按钮的次数-刷新次数为初始状态的实例

    js记录点击某个按钮的次数-刷新次数为初始状态的实例

    下面小编就为大家带来一篇js记录点击某个按钮的次数-刷新次数为初始状态的实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-02-02

最新评论

?


http://www.vxiaotou.com