javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > js for...in 和 for...of 区别

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

作者:fighting ~

for … in 用于迭代对象的可枚举字符串属性,包括自身属性和继承的属性,但不会遍历对象的原型链上的 非可枚举属性,以及对象的方法,这篇文章主要介绍了JS中for...in 和 for...of 的区别,需要的朋友可以参考下

1. 迭代的对象不同

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

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

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

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

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

实际上,两者都不是严格要求的;如果返回没有任何属性的对象,则实际上等价于 { 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
// }

属性描述符

与属性关联的值(仅限数据描述符)。
当且仅当与属性关联的值可以更改时,为 true(仅限数据描述符)。
当且仅当此属性在相应对象的属性枚举中出现时,为 true。
当且仅当此属性描述符的类型可以更改且该属性可以从相应对象中删除时,为 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. 遍历顺序

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

3. 可迭代性要求

总的来说:

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

您可能感兴趣的文章:
阅读全文