ES6学习笔记——迭代器与生成器

10.迭代器和生成器

10-1.迭代器
背景知识
  1. 什么是迭代?

    从一个数据集合中按照一定的顺序,不断取出数据的过程

  2. 迭代和遍历的区别?

    迭代强调的是依次取数据,并不保证取多少,也不保证把所有的数据取完

    遍历强调的是要把整个数据依次全部取出

  3. 迭代器

    对迭代过程的封装,在不同的语言中有不同的表现形式,通常为对象

  4. 迭代模式

    一种设计模式,用于统一迭代过程,并规范了迭代器规格:

     - 迭代器应该具有得到下一个数据的能力
     - 迭代器应该具有判断是否还有后续数据的能力
    
JS中的迭代器

JS规定,如果一个对象具有next方法,并且该方法返回一个对象,该对象的格式如下:

{value:, done: 是否迭代完成}

则认为该对象是一个迭代器

含义:

  • next方法:用于得到下一个数据
  • 返回的对象
    • value下一个数据的值
    • doneboolean,是否迭代完成
 const arr = [1, 2, 3, 4, 5];
        //迭代数组arr
 const iterator = {
     i: 0, //当前的数组下标
     next() {
         var result = {
             value: arr[this.i],
             done: this.i >= arr.length
         }
         this.i++;
         return result;
     }
 }
 //让迭代器不断的取出下一个数据,直到没有数据为止
 let data = iterator.next();
 while (!data.done) { //只要没有迭代完成,则取出数据
     console.log(data.value)
     //进行下一次迭代
     data = iterator.next();
 }

 console.log("迭代完成")
const arr1 = [1, 2, 3, 4, 5];
const arr2 = [6, 7, 8, 9];

// 迭代器创建函数  iterator creator
function createIterator(arr) {
    let i = 0;//当前的数组下标
    return { 
        next() {
            var result = {
                value: arr[i],
                done: i >= arr.length
            }
            i++;
            return result;
        }
    }
}
const iter1 = createIterator(arr1);  
const iter2 = createIterator(arr2);
 // 调用iter1.next();  iter2.next();
// 依次得到斐波拉契数列前面n位的值
 // 1 1 2 3 5 8 13 .....

  //创建一个斐波拉契数列的迭代器
  function createFeiboIterator() {
      let prev1 = 1,
          prev2 = 1, //当前位置的前1位和前2位
          n = 1; //当前是第几位
      return {
          next() {
              let value;
              if (n <= 2) {
                  value = 1;
              } else {
                  value = prev1 + prev2;
              }
              const result = {
                  value,
                  done: false
              };
              prev2 = prev1;
              prev1 = result.value;
              n++;
              return result;
          }
      }
  }
  const iterator = createFeiboIterator();
  //调用 iterator.next();
10-2.可迭代协议 与 for-of 循环

概念回顾

  • 迭代器(iterator):一个具有next方法的对象,next方法返回下一个数据(value)并且能指示是否迭代完成(done)
  • 迭代器创建函数(iterator creator):一个返回迭代器的函数

可迭代协议

ES6规定,如果一个对象具有知名符号属性Symbol.iterator,并且属性值是一个迭代器创建函数,则该对象是可迭代的(iterable)

//可迭代对象
	var obj = {
		[Symbol.iterator]() {
		 	return {
	           next: (){
	           	return{
	           		value : 1,
	           		done : false
	           	}
	           }
	        }
	    }
	}

数组(也包括类数组)本身就是一个可迭代对象

 const arr = [5, 7, 2, 3, 6];

        // const iterator = arr[Symbol.iterator]();
        // let result = iterator.next();
        // while (!result.done) {
        //     const item = result.value; //取出数据
        //     console.log(item);
        //     //下一次迭代
        //     result = iterator.next();
        // }

        for (const item of arr) {
            console.log(item)
        }
for-of 循环

for-of循环用于遍历可迭代对象,格式如下

//迭代完成后循环结束
for(const item of iterable){
    //iterable:可迭代对象
    //item:每次迭代得到的数据
}
//可迭代对象
   var obj = {
       a: 1,
       b: 2,
       [Symbol.iterator]() {
           const keys = Object.keys(this);
           let i = 0;
           return {
               next: () => {
                   const propName = keys[i];
                   const propValue = this[propName];
                   const result = {
                       value: {
                           propName,
                           propValue
                       },
                       done: i >= keys.length
                   }
                   i++;
                   return result;
               }
           }
       }
   }
   for (const item of obj) {
       console.log(item); // {propName:"a", propValue:1}
       				     // {propName:"b", propValue:2}
   }
展开运算符与可迭代对象

展开运算符可以作用于可迭代对象,这样,就可以轻松的将可迭代对象转换为数组。

        var obj = {
            a: 1,
            b: 2,
            [Symbol.iterator]() {
                const keys = Object.keys(this);
                let i = 0;
                return {
                    next: () => {
                        const propName = keys[i];
                        const propValue = this[propName];
                        const result = {
                            value: {
                                propName,
                                propValue
                            },
                            done: i >= keys.length
                        }
                        i++;
                        return result;
                    }
                }
            }
        }

        const arr = [...obj];
        console.log(arr);

        function test(a, b) {
            console.log(a, b)
        }
        test(...obj);  //把每一次迭代的的结果展开放进去
        // {propName: "a", propValue: 1} {propName: "b", propValue: 2}
10-3.生成器 (Generator)
  1. 什么是生成器?

    生成器是一个通过构造函数Generator创建的对象,生成器既是一个迭代器,同时又是一个可迭代对象

  2. 如何创建生成器?

    生成器的创建,必须使用生成器函数(Generator Function)

  3. 如何书写一个生成器函数呢?

//这是一个生成器函数,该函数一定返回一个生成器
function* method(){

}
  1. 生成器函数内部是如何执行的?

    生成器函数内部是为了给生成器的每次迭代提供的数据

    每次调用生成器的next方法,将导致生成器函数运行到下一个yield关键字位置

    yield是一个关键字,该关键字只能在生成器函数内部使用表达“产生”一个迭代数据。

 function* test() {
            console.log("第1次运行")
            yield 1;
            console.log("第2次运行")
            yield 2;
            console.log("第3次运行")
        }
        const generator = test();
        generator.next(); // 第1次运行  {value: 1, done: false}
        generator.next(); // 第2次运行  {value: 2, done: false}  
        generator.next(); // 第3次运行  {value: undefined, done: true}
		const arr1 = [1, 2, 3, 4, 5];  
        const arr2 = [6, 7, 8, 9];

        // 迭代器创建函数  iterator creator
        function* createIterator(arr) {
            for (const item of arr) {
                yield item;
            }
        }
        const iter1 = createIterator(arr1);  // iter1.next()
        const iter2 = createIterator(arr2);  // iter2.next()
		//创建一个斐波拉契数列的迭代器
        function* createFeiboIterator() {
            let prev1 = 1,
                prev2 = 1, //当前位置的前1位和前2位
                n = 1; //当前是第几位
            while (true) {
                if (n <= 2) {
                    yield 1;
                } else {
                    const newValue = prev1 + prev2
                    yield newValue;
                    prev2 = prev1;
                    prev1 = newValue;
                }
                n++;
            }
        }
        const iterator = createFeiboIterator();   // iterator.next()
  1. 生成器有哪些需要注意的细节?

    1). 生成器函数可以有返回值,返回值出现在第一次done为true时的value属性中
    2). 调用生成器的next方法时,可以传递参数,传递的参数会交给yield表达式的返回值
    3). 第一次调用next方法时,传参没有任何意义
    4). 在生成器函数内部,可以调用其他生成器函数,但是要注意加上*

// 生成器函数可以有返回值,返回值出现在第一次done为true时的value属性中
	function* test() {
            console.log("第1次运行")
            yield 1;
            console.log("第2次运行")
            yield 2;
            console.log("第3次运行");
            return 10;
        }
        const generator = test();
        generator.next(); // 第1次运行  {value: 1, done: false}
        generator.next(); // 第2次运行  {value: 2, done: false}  
        generator.next(); // 第3次运行  {value: 10, done: true}
        generator.next(); // {value: undefined, done: true}
//调用生成器的```next```方法时,可以传递参数,传递的参数会交给yield表达式的返回值
	  function* test() {
            console.log("函数开始")
            let info = yield 1;
            console.log(info)
            info = yield 2 + info;
            console.log(info)
        }
        const generator = test();
        generator.next();  // 函数开始    {value: 1, done: false}
        generator.next(5); //   5         {value: 7, done: false}
        generator.next();  // undefined   {value: undefined, done: true}

//  在生成器函数内部,可以调用其他生成器函数,但是要注意加上*号
		function* t1(){
            yield "a"
            yield "b"
        }
        function* test() {
            yield* t1();
            yield 1;
            yield 2;
            yield 3;
        }
        const generator = test();
  1. 生成器的其他API
  • return方法:调用该方法,可以提前结束生成器函数,从而提前让整个迭代过程结束
  • throw方法:调用该方法,可以在生成器中产生一个错误
 function* test() {
	yield 1;
	yield 2;
	yield 3;
 }
 const generator = test();
 generator.next();  // {value: 1, done: false}
 generator.return(); //{value: undefined, done: true} 不传参  
 generator.return(5); //{value: 5, done: true}         传参
	function* test() {
		yield 1;
		yield 2;
		yield 3;
	 }
   const generator = test();
   generator.next();  // {value: 1, done: false}
   generator.throw(new Error("发生错误")); //产生一个错误
10-4.生成器应用—异步任务控制
	  function* task() {
            const d = yield 1;
            console.log(d)
            // //d : 1
            const resp = yield fetch("http://101.132.72.36:5100/api/local")
            const result = yield resp.json();
            console.log(result);
        }
        run(task)


        function run(generatorFunc) {
            const generator = generatorFunc();
            let result = generator.next(); //启动任务(开始迭代), 得到迭代数据
            handleResult();
            //对result进行处理
            function handleResult() {
                if (result.done) {
                    return; //迭代完成,不处理
                }
                //迭代没有完成,分为两种情况
                //1. 迭代的数据是一个Promise
                //2. 迭代的数据是其他数据
                if (typeof result.value.then === "function") {
                    //1. 迭代的数据是一个Promise
                    //等待Promise完成后,再进行下一次迭代
                    result.value.then(data => {
                        result = generator.next(data)
                        handleResult();
                    })
                } else {
                    //2. 迭代的数据是其他数据,直接进行下一次迭代
                    result = generator.next(result.value)
                    handleResult();
                }
            }
        }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值