(Promise、Iterator、for…of 循环)

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由
社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了 Promise  对象。

Promise  对象有以下两个特点。

(1)对象的状态不受外界影响。

(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。

Promise  构造函数接受一个函数作为参数,该函数的两个参数分别是 resolve  和 reject  。

resolve  函数的作用是,将 Promise  对象的状态从“未完成”变为“成功”(即从 pending 变为
resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;

reject  函数的作用是,将 Promise  对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在
异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

Iterator

作用有三个:

一是为各种数据结构,提供一个统一的、简便的访问接口;

二是使得数据结构的成员能够按某种次序排列;

三是 ES6 创造了一种新的遍历命令 for...of  循环,Iterator 接口主要供 for...of  消费。

(1)创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指
针对象。
(2)第一次调用指针对象的 next  方法,可以将指针指向数据结构的第一个成员。
(3)第二次调用指针对象的 next  方法,指针就指向数据结构的第二个成员。
(4)不断调用指针对象的 next  方法,直到它指向数据结构的结束位置。

每一次调用 next  方法,都会返回数据结构的当前成员的信息。具体来说,就是返回一个包
含 value  和 done  两个属性的对象。其中, value  属性是当前成员的值, done  属性是一个
布尔值,表示遍历是否结束。

1.  var it = makeIterator(['a', 'b']);
2.
3.  it.next() // { value: "a", done: false }
4.  it.next() // { value: "b", done: false }
5.  it.next() // { value: undefined, done: true }

next  方法返回一个对象,表示当前数据成员的信息。

这个对象具有 value  和 done  两个属性, value  属性返回当前位置的成员, done  属性是一个布尔值,表示遍历是否结束,即是否还有必要再一次调用 next  方法。

数组

JavaScript 原有的 for...in  循环,只能获得对象的键名,不能直接获取键值。ES6 提供 for...of  循环,允许遍历获得键值。

1.  var arr = ['a', 'b', 'c', 'd'];
2.
3.  for (let a in arr) {
4.  console.log(a); // 0 1 2 3
5.  }
6.
7.  for (let a of arr) {
8.  console.log(a); // a b c d
9.  }

for...of  循环调用遍历器接口,数组的遍历器接口只返回具有数字索引的属性。这一点跟 for...in  循环也不一样。

1.  let arr = [3, 5, 7];
2.  arr.foo = 'hello';
3.
4.  for (let i in arr) {
5.  console.log(i); // "0", "1", "2", "foo"
6.  }
7.
8.  for (let i of arr) {
9.  console.log(i); // "3", "5", "7"
10.  }

上面代码中, for...of  循环不会返回数组 arr  的 foo  属性。

Set 和 Map 结构

Set 和 Map 结构也原生具有 Iterator 接口,可以直接使用 for...of  循环。

1.  var engines = new Set(["Gecko", "Trident", "Webkit", "Webkit"]);
2.  for (var e of engines) {
3.  console.log(e);
4.  }
5.  // Gecko
6.  // Trident
7.  // Webkit
8.
9.  var es6 = new Map();
10.  es6.set("edition", 6);
11.  es6.set("committee", "TC39");
12.  es6.set("standard", "ECMA-262");
13.  for (var [name, value] of es6) {
14.  console.log(name + ": " + value);
15.  }
16.  // edition: 6
17.  // committee: TC39
18.  // standard: ECMA-262

上面代码演示了如何遍历 Set 结构和 Map 结构。值得注意的地方有两个,首先,遍历的顺序是按照
各个成员被添加进数据结构的顺序。其次,Set 结构遍历时,返回的是一个值,而 Map 结构遍历时,
返回的是一个数组,该数组的两个成员分别为当前 Map 成员的键名和键值。

1.  let map = new Map().set('a', 1).set('b', 2);
2.  for (let pair of map) {
3.  console.log(pair);
4.  }
5.  // ['a', 1]
6.  // ['b', 2]
7.
8.  for (let [key, value] of map) {
9.  console.log(key + ' : ' + value);
10.  }
11.  // a : 1
12.  // b : 2

对象

对于普通的对象, for...of  结构不能直接使用,会报错,必须部署了 Iterator 接口后才能使
用。但是,这样情况下, for...in  循环依然可以用来遍历键名。

1.  let es6 = {
2.  edition: 6,
3.  committee: "TC39",
4.  standard: "ECMA-262"
5.  };
6.
7.  for (let e in es6) {
8.  console.log(e);
9.  }
10.  // edition
11.  // committee
12.  // standard
13.
14.  for (let e of es6) {
15.  console.log(e);
16.  }
17.  // TypeError: es6[Symbol.iterator] is not a function

上面代码表示,对于普通的对象, for...in  循环可以遍历键名, for...of  循环会报错。
一种解决方法是,使用 Object.keys  方法将对象的键名生成一个数组,然后遍历这个数组。

与其他遍历语法的比较

数组提供内置的 forEach  方法。

1.  myArray.forEach(function (value) {
2.  console.log(value);
3.  });

这种写法的问题在于,无法中途跳出 forEach  循环, break  命令或 return  命令都不能奏效。

for...in  循环可以遍历数组的键名。

1.  for (var index in myArray) {
2.  console.log(myArray[index]);
3.  }

for...in  循环有几个缺点

1、数组的键名是数字,但是 for...in  循环是以字符串作为键名“0”、“1”、“2”等等。
2、for...in  循环不仅遍历数字键名,还会遍历手动添加的其他键,甚至包括原型链上的键。
3、某些情况下, for...in  循环会以任意顺序遍历键名。

总之, for...in  循环主要是为遍历对象而设计的,不适用于遍历数组。

for...of  循环相比上面几种做法,有一些显著的优点。

1.  for (let value of myArray) {
2.  console.log(value);
3.  }

1、有着同 for...in  一样的简洁语法,但是没有 for...in  那些缺点。
2、不同于 forEach  方法,它可以与 break  、 continue  和 return  配合使用。
3、提供了遍历所有数据结构的统一操作接口。

posted @ 2021-05-21 16:40  铁打的代码流水的bug  阅读(139)  评论(0)    收藏  举报