• 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 'auD83DuDC0A') {
      console.log(x);
    }
    // 'a'
    // 'uD83DuDC0A'
    • 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);

  • 相关阅读:
    告别零码软件
    win+mingw+libxml2试用笔记
    beacon with java 1.7 on fedora
    mininet指令详解
    java Socket完美实例
    gnome3 下 qt 应用极其丑陋的解决方案
    org.apache.log4j Class Level
    Mac如何修改文本文件编码
    unity性能优化相关
    平面图判定
  • 原文地址:https://www.cnblogs.com/liangtao999/p/11710787.html
Copyright © 2020-2023  润新知