(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、提供了遍历所有数据结构的统一操作接口。

浙公网安备 33010602011771号