生成器和迭代器 GeneratorFunction和Generator GeneratorFunction 和 Generator 在JavaScript中,GeneratorFunction和Generator是ES6引入的两个重要概念,它们主要用于处理异步编程和迭代器的创建。
1. GeneratorFunction GeneratorFunction是一种特殊的函数,通过在function关键字后面加上一个星号(*)来定义。这种函数不会立即执行其内部代码,而是返回一个Generator对象。GeneratorFunction使用yield关键字来暂停和恢复函数的执行。基本语法:
1 2 3 4 5 6 function * generatorFunction ( ) { yield 1 ; yield 2 ; yield 3 ; return 4 ; }
示例:
1 2 3 4 5 6 7 8 9 10 11 function * generatorFunction ( ) { console .log ("Start" ); yield 1 ; console .log ("Resume" ); yield 2 ; console .log ("End" ); } const gen = generatorFunction ();console .log (gen.next ()); console .log (gen.next ()); console .log (gen.next ());
输出:
1 2 3 4 5 6 Start { value: 1, done: false } Resume { value: 2, done: false } End { value: undefined, done: true }
2. Generator Generator是GeneratorFunction返回的迭代器对象。通过调用Generator对象的next()方法,可以控制函数的执行流程,每次调用next()方法会执行到下一个yield语句并返回相应的值。基本特性:
定义方式 :使用function*语法定义。
返回值 :调用GeneratorFunction时返回一个Generator对象。
yield关键字 :用于生成值并暂停函数执行。
next()方法 :用于恢复函数执行并获取下一个值。示例:
1 2 3 4 5 6 7 8 function * generatorFunction ( ) { yield 'hello' ; yield 'world' ; } const gen = generatorFunction ();console .log (gen.next ().value ); console .log (gen.next ().value ); console .log (gen.next ().value );
3. Generator的异步编程应用 Generator在异步编程中非常有用,可以通过yield关键字暂停和恢复异步任务的执行。示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 function fetch (url ) { return new Promise ((resolve, reject ) => { console .log ('异步操作执行中:' + url); setTimeout (() => { console .log ('异步操作完成:' + url); resolve ({ status : 1 , msg : '异步操作完成:' + url, data : null }); }, 2000 ); }); } function * taskGenerator ( ) { const task1 = yield fetch ('https://api.example.com/task1' ); const task2 = yield fetch ('https://api.example.com/task2' ); const task3 = yield fetch ('https://api.example.com/task3' ); console .log (task1); console .log (task2); console .log (task3); } function executeGenerator (generator ) { const iterator = generator (); function handle (iteratorResult ) { if (iteratorResult.done ) { return Promise .resolve (iteratorResult.value ); } return Promise .resolve (iteratorResult.value ) .then (res => handle (iterator.next (res))) .catch (err => iterator.throw (err)); } try { return handle (iterator.next ()); } catch (err) { return Promise .reject (err); } } executeGenerator (taskGenerator) .then (() => { console .log ('所有任务完成' ); }) .catch (err => { console .error ('执行过程中出错:' , err); });
4. 与async/await结合使用 Generator和async/await可以很好地结合使用,以简化异步编程,并使代码更具可读性和可维护性。示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 function getData ( ) { return new Promise (resolve => { setTimeout (() => { resolve ('数据' ); }, 1000 ); }); } function * fetchAsyncData ( ) { try { const data = yield getData (); console .log ('获取到的数据:' , data); const moreData = yield getData (); console .log ('更多的数据:' , moreData); return '完成' ; } catch (error) { console .error ('发生错误:' , error); return '出错' ; } } async function fetchData ( ) { try { const generator = fetchAsyncData (); let result = generator.next (); while (!result.done ) { result = await result.value ; result = generator.next (result); } console .log ('最终结果:' , result.value ); } catch (error) { console .error ('发生错误:' , error); } } fetchData ();
通过结合使用 Generator 和 async/await,可以以顺序和分步的方式处理异步操作,使代码更清晰、易读,并且能够很好地处理异常情况。
迭代器(Iterator) 迭代器是一种设计模式,用于顺序访问一个聚合对象中的各个元素,而不暴露其内部的表示形式。在JavaScript中,迭代器是一个对象,它实现了Iterator接口,该接口定义了两个方法:next()和return()。
1. 迭代器接口 基本方法:
next() :返回一个包含两个属性的对象:value和done。
value:当前迭代的值。
done:一个布尔值,表示迭代是否已经完成。如果done为true,则value通常为undefined。
return(value) :提前结束迭代器,并返回一个done为true的对象。value是可选的返回值。
2. 创建迭代器 可以通过实现Iterator接口来创建自定义迭代器。示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 const myIterator = { data : [1 , 2 , 3 ], next : function ( ) { if (this .data .length > 0 ) { return { value : this .data .shift (), done : false }; } else { return { value : undefined , done : true }; } } }; console .log (myIterator.next ()); console .log (myIterator.next ()); console .log (myIterator.next ()); console .log (myIterator.next ());
3. 使用Symbol.iterator方法 为了使对象可迭代,可以实现Symbol.iterator方法,该方法返回一个迭代器对象。示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const myIterable = { data : [1 , 2 , 3 ], [Symbol .iterator ]: function ( ) { let index = 0 ; return { next : () => { if (index < this .data .length ) { return { value : this .data [index++], done : false }; } else { return { value : undefined , done : true }; } } }; } }; for (let value of myIterable) { console .log (value); }
4. 原生可迭代对象 JavaScript中许多内置对象已经实现了Symbol.iterator方法,因此它们是可迭代的,可以直接使用for...of循环。示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 const array = [1 , 2 , 3 ];for (let value of array) { console .log (value); } const string = 'hello' ;for (let char of string) { console .log (char); } const map = new Map ([[1 , 'one' ], [2 , 'two' ]]);for (let [key, value] of map) { console .log (key, value); } const set = new Set ([1 , 2 , 3 ]);for (let value of set) { console .log (value); }
5. 迭代器的高级用法 生成器作为迭代器: 生成器函数(function*)返回一个迭代器对象,可以非常方便地创建复杂的迭代逻辑。示例:
1 2 3 4 5 6 7 8 9 function * generatorFunction ( ) { yield 1 ; yield 2 ; yield 3 ; } const gen = generatorFunction ();for (let value of gen) { console .log (value); }
自定义迭代器: 可以自定义迭代器来处理复杂的集合或数据结构。示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Range { constructor (start, end ) { this .start = start; this .end = end; } [Symbol .iterator ]() { let current = this .start ; let end = this .end ; return { next : () => { if (current <= end) { return { value : current++, done : false }; } else { return { value : undefined , done : true }; } } }; } } const range = new Range (1 , 5 );for (let value of range) { console .log (value); }
总结 迭代器是一种强大的设计模式,可以用于顺序访问集合中的元素,而不暴露其内部结构。在JavaScript中,通过实现Symbol.iterator方法或使用生成器函数,可以轻松创建自定义迭代器,从而实现更灵活和高效的集合遍历。
生成器(Generator)和迭代器(Iterator) 在JavaScript中,生成器(Generator)和迭代器(Iterator)是两个密切相关但又有所不同的概念。它们共同的目标是提供一种顺序访问集合或数据流的方式,但实现和使用方式有所不同。
1. 迭代器(Iterator) 定义: 迭代器是一种设计模式,用于顺序访问一个聚合对象中的各个元素,而不暴露其内部的表示形式。在JavaScript中,迭代器是一个对象,它实现了Iterator接口,该接口定义了两个方法:next()和return()。基本方法:
next() :返回一个包含两个属性的对象:value和done。
value:当前迭代的值。
done:一个布尔值,表示迭代是否已经完成。如果done为true,则value通常为undefined。
return(value) :提前结束迭代器,并返回一个done为true的对象。value是可选的返回值。示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 const myIterator = { data : [1 , 2 , 3 ], next : function ( ) { if (this .data .length > 0 ) { return { value : this .data .shift (), done : false }; } else { return { value : undefined , done : true }; } } }; console .log (myIterator.next ()); console .log (myIterator.next ()); console .log (myIterator.next ()); console .log (myIterator.next ());
使用Symbol.iterator方法: 为了使对象可迭代,可以实现Symbol.iterator方法,该方法返回一个迭代器对象。示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const myIterable = { data : [1 , 2 , 3 ], [Symbol .iterator ]: function ( ) { let index = 0 ; return { next : () => { if (index < this .data .length ) { return { value : this .data [index++], done : false }; } else { return { value : undefined , done : true }; } } }; } }; for (let value of myIterable) { console .log (value); }
2. 生成器(Generator) 定义: 生成器是一种特殊的函数,通过在function关键字后面加上一个星号(*)来定义。这种函数不会立即执行其内部代码,而是返回一个Generator对象。Generator对象是一个迭代器,可以通过调用其next()方法来控制函数的执行流程,每次调用next()方法会执行到下一个yield语句并返回相应的值。基本语法:
1 2 3 4 5 6 function * generatorFunction ( ) { yield 1 ; yield 2 ; yield 3 ; return 4 ; }
示例:
1 2 3 4 5 6 7 8 9 10 11 function * generatorFunction ( ) { console .log ("Start" ); yield 1 ; console .log ("Resume" ); yield 2 ; console .log ("End" ); } const gen = generatorFunction ();console .log (gen.next ()); console .log (gen.next ()); console .log (gen.next ());
输出:
1 2 3 4 5 6 Start { value: 1, done: false } Resume { value: 2, done: false } End { value: undefined, done: true }
3. 生成器和迭代器的关系 生成器函数返回的Generator对象是一个迭代器,因此生成器可以看作是迭代器的一种更高级的实现方式。生成器通过yield关键字来暂停和恢复函数的执行,使得编写复杂的迭代逻辑变得更加简单和直观。示例:
1 2 3 4 5 6 7 8 9 function * generatorFunction ( ) { yield 1 ; yield 2 ; yield 3 ; } const gen = generatorFunction ();for (let value of gen) { console .log (value); }
4. 生成器的异步编程应用 生成器在异步编程中非常有用,可以通过yield关键字暂停和恢复异步任务的执行。结合async/await,可以进一步简化异步编程的复杂性。示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 function fetch (url ) { return new Promise ((resolve, reject ) => { console .log ('异步操作执行中:' + url); setTimeout (() => { console .log ('异步操作完成:' + url); resolve ({ status : 1 , msg : '异步操作完成:' + url, data : null }); }, 2000 ); }); } function * taskGenerator ( ) { const task1 = yield fetch ('https://api.example.com/task1' ); const task2 = yield fetch ('https://api.example.com/task2' ); const task3 = yield fetch ('https://api.example.com/task3' ); console .log (task1); console .log (task2); console .log (task3); } function executeGenerator (generator ) { const iterator = generator (); function handle (iteratorResult ) { if (iteratorResult.done ) { return Promise .resolve (iteratorResult.value ); } return Promise .resolve (iteratorResult.value ) .then (res => handle (iterator.next (res))) .catch (err => iterator.throw (err)); } try { return handle (iterator.next ()); } catch (err) { return Promise .reject (err); } } executeGenerator (taskGenerator) .then (() => { console .log ('所有任务完成' ); }) .catch (err => { console .error ('执行过程中出错:' , err); });
5. 与async/await结合使用 Generator和async/await可以很好地结合使用,以简化异步编程,并使代码更具可读性和可维护性。示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 function getData ( ) { return new Promise (resolve => { setTimeout (() => { resolve ('数据' ); }, 1000 ); }); } async function fetchData ( ) { const data1 = await getData (); console .log ('获取到的数据1:' , data1); const data2 = await getData (); console .log ('获取到的数据2:' , data2); return '完成' ; } fetchData ().then (result => { console .log ('最终结果:' , result); });
总结
迭代器 :是一种设计模式,用于顺序访问集合中的元素,不暴露内部结构。通过实现Symbol.iterator方法,可以使对象可迭代。
生成器 :是一种特殊的函数,通过function*定义,返回一个迭代器对象。生成器通过yield关键字暂停和恢复函数的执行,简化了复杂迭代逻辑的编写。
结合使用 :生成器和async/await可以结合使用,进一步简化异步编程,使代码更清晰、易读,并且能够很好地处理异常情况。 通过理解和使用生成器和迭代器,可以更高效地处理集合和异步任务,提升代码的可维护性和可读性。
返回值是迭代器 在JavaScript中,有多种方式可以获取迭代器。以下是一些常见的函数和方法,它们的返回值是迭代器:
1. 生成器函数(Generator Function) 生成器函数通过在function关键字后面加上一个星号(*)来定义。调用生成器函数会返回一个Generator对象,该对象是一个迭代器。示例:
1 2 3 4 5 6 7 8 9 10 function * generatorFunction ( ) { yield 1 ; yield 2 ; yield 3 ; } const gen = generatorFunction ();console .log (gen.next ()); console .log (gen.next ()); console .log (gen.next ()); console .log (gen.next ());
2. 数组的[Symbol.iterator]方法 数组对象实现了Symbol.iterator方法,调用该方法会返回一个迭代器。示例:
1 2 3 4 5 6 const array = [1 , 2 , 3 ];const iterator = array[Symbol .iterator ]();console .log (iterator.next ()); console .log (iterator.next ()); console .log (iterator.next ()); console .log (iterator.next ());
3. 字符串的[Symbol.iterator]方法 字符串对象也实现了Symbol.iterator方法,调用该方法会返回一个迭代器。示例:
1 2 3 4 5 6 7 8 const string = 'hello' ;const iterator = string[Symbol .iterator ]();console .log (iterator.next ()); console .log (iterator.next ()); console .log (iterator.next ()); console .log (iterator.next ()); console .log (iterator.next ()); console .log (iterator.next ());
4. Map对象的[Symbol.iterator]方法 Map对象实现了Symbol.iterator方法,调用该方法会返回一个迭代器,迭代器的每个值是一个键值对数组。示例:
1 2 3 4 5 const map = new Map ([[1 , 'one' ], [2 , 'two' ]]);const iterator = map[Symbol .iterator ]();console .log (iterator.next ()); console .log (iterator.next ()); console .log (iterator.next ());
5. Set对象的[Symbol.iterator]方法 Set对象实现了Symbol.iterator方法,调用该方法会返回一个迭代器,迭代器的每个值是集合中的一个元素。示例:
1 2 3 4 5 6 const set = new Set ([1 , 2 , 3 ]);const iterator = set[Symbol .iterator ]();console .log (iterator.next ()); console .log (iterator.next ()); console .log (iterator.next ()); console .log (iterator.next ());
6. arguments对象的[Symbol.iterator]方法 在函数内部,arguments对象也实现了Symbol.iterator方法,调用该方法会返回一个迭代器,迭代器的每个值是函数的参数。示例:
1 2 3 4 5 6 7 8 function test ( ) { const iterator = arguments [Symbol .iterator ](); console .log (iterator.next ()); console .log (iterator.next ()); console .log (iterator.next ()); console .log (iterator.next ()); } test (1 , 2 , 3 );
7. 自定义对象的[Symbol.iterator]方法 可以通过在自定义对象上实现Symbol.iterator方法,使其返回一个迭代器。示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 const myIterable = { data : [1 , 2 , 3 ], [Symbol .iterator ]: function ( ) { let index = 0 ; return { next : () => { if (index < this .data .length ) { return { value : this .data [index++], done : false }; } else { return { value : undefined , done : true }; } } }; } }; const iterator = myIterable[Symbol .iterator ]();console .log (iterator.next ()); console .log (iterator.next ()); console .log (iterator.next ()); console .log (iterator.next ());
8. Array.prototype.entries()、Array.prototype.keys()、Array.prototype.values() 这些方法返回的都是迭代器,分别用于迭代数组的键值对、键和值。示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 const array = [1 , 2 , 3 ];const entriesIterator = array.entries ();console .log (entriesIterator.next ()); console .log (entriesIterator.next ()); console .log (entriesIterator.next ()); console .log (entriesIterator.next ()); const keysIterator = array.keys ();console .log (keysIterator.next ()); console .log (keysIterator.next ()); console .log (keysIterator.next ()); console .log (keysIterator.next ()); const valuesIterator = array.values ();console .log (valuesIterator.next ()); console .log (valuesIterator.next ()); console .log (valuesIterator.next ()); console .log (valuesIterator.next ());
9. Map.prototype.entries()、Map.prototype.keys()、Map.prototype.values() 这些方法返回的都是迭代器,分别用于迭代Map的键值对、键和值。示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 const map = new Map ([[1 , 'one' ], [2 , 'two' ]]);const entriesIterator = map.entries ();console .log (entriesIterator.next ()); console .log (entriesIterator.next ()); console .log (entriesIterator.next ()); const keysIterator = map.keys ();console .log (keysIterator.next ()); console .log (keysIterator.next ()); console .log (keysIterator.next ()); const valuesIterator = map.values ();console .log (valuesIterator.next ()); console .log (valuesIterator.next ()); console .log (valuesIterator.next ());
10. Set.prototype.values() Set.prototype.values()方法返回一个迭代器,用于迭代Set中的值。注意,Set的values()方法和[Symbol.iterator]方法是等价的。示例:
1 2 3 4 5 6 7 const set = new Set ([1 , 2 , 3 ]);const valuesIterator = set.values ();console .log (valuesIterator.next ()); console .log (valuesIterator.next ()); console .log (valuesIterator.next ()); console .log (valuesIterator.next ());
总结 这些方法和函数返回的都是迭代器,可以通过调用next()方法来逐个获取集合中的元素。迭代器在处理集合和数据流时非常有用,尤其是在需要逐个处理元素或处理异步数据时。