javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > JavaScript for...in、for...of和for await...of

JavaScript中for...in、for...of和for await...of迭代方式

投稿:zx

方法

前言

for...infor...offor await...ofJavaScript中三种不同的迭代方式,我们也经常会用到,但你真的了解它们吗?并知道怎么选择它们吗?

for...in

for...in

MDNfor...in 语句以任意顺序迭代一个对象的除Symbol以外的可枚举属性,包括继承的可枚举属性

那么什么是可枚举属性

JavaScript中,可枚举性(enumerable)是是对象属性的一种特性,用于指示该属性是否可以通过循环访问,常见的可枚举的数据类型有:object、array、string、typedArray(类数组)

我们可以通过Object.getOwnPropertyDescriptor 方法获取对象属性的描述对象。该方法接受两个参数:要获取的属性所在的对象和属性名。它返回一个对象,该对象包含以下属性:

const obj = {
  name: "张三",
  age: 18,
};

const desc = Object.getOwnPropertyDescriptor(obj, "name");

console.log(desc);

image-20230415210955651

普通对象的属性默认都是可枚举的,我们一般用于获取对象的属性名(键)

const obj = {
  name: "张三",
  age: 10,
  hello() {
    console.log("hello");
  },
};
for (const key in obj) {
  console.log(key); // name age hello
}

但是有两个点我们要注意:

我们以第一个点为例

// 定义一个父级对象
const parent = {
  name: "张三",
  say() {
    console.log(this.name);
  },
};

// 以parent为原型,定义一个子级对象
const son = Object.create(parent);
son.age = 19;

// 遍历子级对象的属性
for (const key in son) {
  console.log(key); // 输出 age name say
}

那么如何让for...in只遍历自己的属性呢?我们可以用obj.hasOwnProperty()来判断是否是自己的属性

修改如下:

for (const key in son) {
  if (son.hasOwnProperty(key)) {
    console.log(key); // 输出 age
  }
}

再说第二个点,如果键名都是字符串,那么顺序没问题,这也是我们大多数的使用情况

const obj = {
  name: "张三",
  age: 18,
  say() {
    console.log(this.name);
  },
};

for (const key in obj) {
  console.log(key); // name age say
}

要是出现其他类型的键名,顺序就有问题了

const obj = {
  name: "张三",
  age: 18,
  say() {
    console.log(this.name);
  },
  2: "数字2",
};

for (const key in obj) {
  console.log(key); // 2 name age say
}

for...of

说完for...in,我们再来说说for...of

MDNfor...of语句可迭代对象(包括Array, Map, Set, String, TypedArray, arguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句

那么什么又是可迭代对象呢?

说到可迭代对象,就要讲到迭代器了,迭代器是一种对象,它提供统一的接口,为不同的集合(Object、Array、Set、Map)提供了统一的访问机制。总的来说,可迭代对象就是实现Symbol.iterator方法的对象

注意:普通对象不是可迭代对象,所以,for...of是不能用来遍历普通对象的

还有一个直观感受就是for...in用于获取键(key)for...of用于获取值(value)

const arr = ["张三", "李四", "王五"];

for (const key in arr) {
  console.log(key); // 0 1 2
}

for (const value of arr) {
  console.log(value); // "张三", "李四", "王五"
}

但我们一般不用于遍历数组,我们用于遍历MapSet,它们的实例身上都有如下几个方法,用于返回一个数组(数组就是一个可迭代对象)

以Set为例

const set = new Set(["red", "green", "blue"]);

// 因为set只有值,没有键,结果就是这样了
for (const key of set.keys()) {
  console.log(key);
}
for (const key of set.values()) {
  console.log(key);
}
for (const [key, value] of set.entries()) {
  console.log(key, value);
}

image-20230415220638932

再来看看Map

const map = new Map([
  ["name", "张三"],
  ["age", 19],
]);

for (const key of map.keys()) {
  console.log(key);
}
for (const key of map.values()) {
  console.log(key);
}
for (const [key, value] of map.entries()) {
  console.log(key, value);
}

image-20230415220554579

我们也可以使用for...of来遍历普通对象,借助Object.keys()Object.values()Object.entries(),它们都可以把一个对象包装成迭代器,使用起来就和Map差不多了。

const obj = {
  name: "张三",
  age: 19,
};

for (const key of Object.keys(obj)) {
  console.log(key);
}
for (const key of Object.values(obj)) {
  console.log(key);
}
for (const [key, value] of Object.entries(obj)) {
  console.log(key, value);
}

image-20230415220953576

如何选择for...infor...of

如果你只是想遍历对象的属性名,用for...in,其他的像MapSetfor...of

for await...of

for await...ofES9才有的新东西。

MDNfor await...of 语句创建一个循环,该循环遍历异步可迭代对象以及同步可迭代对象,包括:内置的StringArray,类似数组对象 (例如argumentsNodeList),TypedArrayMapSet 和用户定义的异步/同步迭代器。它使用对象的每个不同属性的值调用要执行的语句来调用自定义迭代钩子。

需要注意的是:我们知道await需要配合async一起使用,所以,使用了for await...of,外层需要async

注意和for...of的区别,用于遍历异步可迭代对象,当然也可以遍历同步可迭代对象,但这样就失去了使用意义。

我们一个例子来讲解:

function createAsyncIterable(delay) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(delay);
    }, delay);
  });
}

// 数组就是一个可迭代对象
const asyncIterable = [createAsyncIterable(2000), createAsyncIterable(1000), createAsyncIterable(3000)];

async function main() {
  for await (const item of asyncIterable) {
    console.log(item);
  }
}

main();

image-20230415224730155

它其实相当于

function createAsyncIterable(delay) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(delay);
    }, delay);
  });
}

async function main() {
  const p1 = await createAsyncIterable(2000);
  console.log(p1);
  const p2 = await createAsyncIterable(1000);
  console.log(p2);
  const p3 = await createAsyncIterable(3000);
  console.log(p3);
}

main();

最后

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

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