ES6 Iterator迭代器和for...of循环

ES5中遍历集合通常都是 for循环,数组还有 forEach 方法,对象就是 for-in,

var mycars = {a:2,b:3,c:4}
for(var key in mycars)
{
    key;//a  b  c
    mycars[key]; //2 3 4
}

ES6 中又添加了 Map 和 Set,而迭代器可以统一处理所有集合数据的方法。迭代器是一个接口,只要你这个数据结构暴露了一个iterator的接口,那就可以完成迭代。ES6创造了一种新的遍历命令for...of循环,Iterator接口主要供for...of消费。

迭代器是带有特殊接口的对象。含有一个next()方法,调用返回一个包含两个属性的对象,分别是valuedone,value表示当前位置的值,done表示是否迭代完,当为true的时候,调用next就无效了。

一个数据结构只要具有 Symbol.iterator 数据,就可以认为是“可遍历的”(iterable)。

const items = ["zero", "one", "two"];
const it = items[Symbol.iterator]();

it.next();
// >{value: "zero", done: false}
it.next();
// >{value: "one", done: false}
it.next();
// >{value: "two", done: false}
it.next();
// >{value: undefined, done: true}
        var map=new Map([["a",1],["b",2]]);
        var iterator=map.keys();
        let k;
        do {
            k = iterator.next();
            console.log(k.value);
        } while(!k.done);

可迭代的数据结构

以下是可迭代的值:

  • Array
  • Map
  • Set
  • String
  • TypedArray(一种通用的固定长度缓冲区类型,允许读取缓冲区中的二进制数据)
  • 函数中的 arguments 对象
  • NodeList 对象

      注:普通对象不能迭代。做如下处理,可使对象可以迭代

// code1
function Obj(value) {
    this.value = value;
    this.next = null;
}
Obj.prototype[Symbol.iterator] = function() {
    var iterator = {
        next: next
    };
    var current = this;
    function next() {
        if (current) {
            var value = current.value;
            current = current.next;
            return {
                done: false,
                value: value
            };
        } else {
            return {
                done: true
            };
        }
    }
    return iterator;
}
var one = new Obj(1);
var two = new Obj(2);
var three = new Obj(3);
one.next = two;
two.next = three;
for (var i of one) {
    console.log(i);
}
// 1
// 2
// 3

 

调用 Iterator 接口的场合

(1) 解构赋值

// code2
let set = new Set().add('a').add('b').add('c');
let [x,y] = set;
// x='a'; y='b'
let [first, ...rest] = set;
// first='a'; rest=['b','c'];

(2) 扩展运算符

// code3
// 例一
var str = 'hello';
[...str] // ['h','e','l','l','o']
// 例二
let arr = ['b', 'c'];
['a', ...arr, 'd']
// ['a', 'b', 'c', 'd']

(3)Generator 函数中的 yield* 表达式

// code4
let generator = function* () {
  yield 1;
  yield* [2,3,4];
  yield 5;
};
var iterator = generator();
iterator.next() // { value: 1, done: false }
iterator.next() // { value: 2, done: false }
iterator.next() // { value: 3, done: false }
iterator.next() // { value: 4, done: false }
iterator.next() // { value: 5, done: false }
iterator.next() // { value: undefined, done: true }

(4)其它场合

  • for..of
  • Array.from
  • Map()、Set()、WeakMap()、WeakSet()
  • Promise.all()
  • Promise.race()
for...of 循环的优势

数组 forEach 缺点:无法中途跳出 forEach 循环,break 命令或 return 命令都不能生效

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

对象 for...in 的循环的缺点:

  • for...in 遍历主要是为遍历对象而设计的,不适用于遍历数组
  • 数组的键名是数字,但是 for...in 循环是以字符串作为键名,“0”、“1”、“2”等。
  • for...in 循环不仅可以遍历数字键名,还会遍历手动添加的其他键,甚至包括原型链上的键。
  • 某些情况下,for...in 循环会议任意顺序遍历键名
for (var index in myArray) 
  console.log(myArray[index]);
};

for...of 有哪些显著的优点呢?

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

1、数组

for...of 循环调用遍历器接口,数组的遍历器接口只返回具有数字索引的值

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

2、Map 和 Set 结构

for...of 循环遍历Map 和 Set 结构时,遍历的顺序是按照各个成员被添加进数据结构的顺序,Set 结构遍历时返回的是一个值,而 Map 结构遍历时返回的是一个数组

3、类数组对象

  • 字符串
// 普通的字符串遍历
let str = "yuan";
for (let s of str) {
  console.log(s); // y u a n
}

// 遍历含有 32位 utf-16字符的字符串
for (let x of 'a\uD83D\uDC0A') {
  console.log(x);
}
// 'a'
// '\uD83D\uDC0A'
  • DOM NodeList 对象
let paras = document.querySelectorAll("p");
for (let p of paras) {
  p.classList.add("test");
}
  • arguments对象
function printArgs() {
  for (let x of arguments) {
    console.log(x);
  }
}
printArgs("a", "n");
// "a"
// "n"

 

没有 Iterator 接口类数组对象的遍历处理
借用 Array.from 方法处理

let arrayLike = {
    length: 2,
    0 : 'a',
    1 : 'b'
};
// 报错
for (let x of arrayLike) {
    console.log(x);
}
// 正确
for (let x of Array.from(arrayLike)) {
    console.log(x);
}

迭代器应用实例

1、斐波那契数列

var it = { [Symbol.iterator]() {
        return this
    },
    n1: 0,
    n2: 1,
    next() {
        let temp1 = this.n1,
        temp2 = this.n2;
        [this.n1, this.n2] = [temp2, temp1 + temp2]
        return {
            value: temp1,
            done: false
        }
    }
}

for (var i = 0; i < 20; i++) {
    console.log(it.next())
}

 

2、任务队列迭代器

3、延迟执行

 

学习原文

var map=new Map([["a",1],["b",2]]);var iterator=map.keys();let k;do {k = iterator.next();console.log(k.value);} while(!k.done);

posted @ 2019-10-20 23:02  梁涛999  阅读(135)  评论(0编辑  收藏  举报