
目录
迭代器(iterator),使用户在容器对象(container,例如链表或数组)上遍访的对象,使用该接口无需关心对象的内部实现细节。
从迭代器的定义我们可以看出来,迭代器是帮助我们对某个数据结构进行遍历的对象
在JavaScript中,迭代器也是一个具体的对象
这个对象需要符合迭代器协议(iterator protocol):
next方法有如下的要求:
- const arr = ['a', 'b', 'c', 'd'];
-
- // 创建一个arr的迭代器对象
- // 1. 创建一个索引
- let index = 0;
- const arrIterator = {
- // 2. 必须实现next方法
- next() {
- // 没有迭代完成
- if (index < arr.length) {
- // 3. 返回两个参数 done -> 是否完成 value : 值 执行完后index++
- return { done: false, value: arr[index++] };
- } else {
- // 迭代完成 value也可不写
- return { done: true, value: undefined };
- }
- }
- };
-
- console.log(arrIterator.next()); // { done: false, value: 'a' }
- console.log(arrIterator.next()); // { done: false, value: 'b' }
- console.log(arrIterator.next()); // { done: false, value: 'c' }
- console.log(arrIterator.next()); // { done: false, value: 'd' }
- console.log(arrIterator.next()); // { done: true, value: undefined }
- console.log(arrIterator.next()); // { done: true, value: undefined }
- const arr = ['a', 'b', 'c', 'd'];
- const nums = [11, 22, 33];
-
- function createArrayIterator(arr) {
- let index = 0;
- // 1. 返回这个迭代器对象
- return {
- // 2. 必须实现next方法
- next() {
- // 3. 返回两个参数 done -> 是否完成 value : 值 执行完后index++
- return { done: index >= arr.length, value: arr[index++] };
- }
- };
- }
-
- const arrIterator = createArrayIterator(arr);
- console.log(arrIterator.next()); // { done: false, value: 'a' }
- console.log(arrIterator.next()); // { done: false, value: 'b' }
- console.log(arrIterator.next()); // { done: false, value: 'c' }
- console.log(arrIterator.next()); // { done: false, value: 'd' }
- console.log(arrIterator.next()); // { done: true, value: undefined }
- console.log(arrIterator.next()); // { done: true, value: undefined }
-
- const numsIterator = createArrayIterator(nums);
- console.log(numsIterator.next()); // { done: false, value: 11 }
- console.log(numsIterator.next()); // { done: false, value: 22 }
- console.log(numsIterator.next()); // { done: false, value: 33 }
- console.log(numsIterator.next()); // { done: true, value: undefined }
- console.log(numsIterator.next()); // { done: true, value: undefined }
- console.log(numsIterator.next()); // { done: true, value: undefined }
可迭代对象 :
转变为可迭代对象的好处 :
- // 一、拥有[Symbol.iterator]方法, 并且内部实现了迭代器的对象,就称之为 => 可迭代对象
- const obj = {
- name: 'coder',
- // 1. 测试数据
- arr: ['a', 'b', 'c', 'd'],
- // 2. 必须有这个属性名实现的方法
- [Symbol.iterator]() {
- // 3. 内部实现一个迭代器
- let index = 0;
- // 4. 返回这个迭代器
- return {
- next: () => {
- // 这里为了使用this,需要使用箭头函数,你懂的,找到外层的this
- return { done: index >= this.arr.length, value: this.arr[index++] };
- }
- };
- }
- };
-
- // 二、使用迭代器
- const objIterator = obj[Symbol.iterator]();
- console.log(objIterator.next()); // { done: false, value: 'a' }
- console.log(objIterator.next()); // { done: false, value: 'b' }
- console.log(objIterator.next()); // { done: false, value: 'c' }
- console.log(objIterator.next()); // { done: false, value: 'd' }
- console.log(objIterator.next()); // { done: true, value: undefined }
- console.log(objIterator.next()); // { done: true, value: undefined }
- console.log(objIterator.next()); // { done: true, value: undefined }
-
- // 三、可迭代对象可以使用for...of循环
- // 返回的值,就是跌打器中的各个有值的value
- for (const item of obj) {
- console.log(item); // a b c d
- }
- // 一、拥有[Symbol.iterator]方法, 并且内部实现了迭代器的对象,就称之为 => 可迭代对象
- /*
- 1.必须实现一个特定的函数: [Symbol.iterator]
- 2.这个函数需要返回一个迭代器(这个迭代器用于迭代当前的对象)
- */
- const obj = {
- name: 'coder',
- age: 18,
- info: ['abc', 'acb', 'ope'],
- // 2. 必须有这个属性名实现的方法
- [Symbol.iterator]() {
- // 3. 内部实现一个迭代器
- let index = 0;
- const entries = Object.entries(this);
- // 4. 返回这个迭代器
- return {
- next: () => {
- if (index < entries.length) {
- const [key, value] = entries[index++];
- return { done: false, value: { key, value } };
- } else {
- return { done: true };
- }
- }
- };
- }
- };
-
- // 二、使用迭代器
- const objIterator = obj[Symbol.iterator]();
- console.log(objIterator.next()); // { done: false, value: { key: 'name', value: 'coder' } }
- console.log(objIterator.next()); // { done: false, value: { key: 'age', value: 18 } }
- console.log(objIterator.next()); // { done: false, value: { key: 'info', value: [ 'abc', 'acb', 'ope' ] } }
- console.log(objIterator.next()); // { done: true }
- console.log(objIterator.next()); // { done: true }
-
- // 三、可迭代对象可以使用for...of循环
- // 返回的值,就是跌打器中的各个有值的value
- // 本质就是调用迭代器的next
- for (const item of obj) {
- console.log(item);
- /**
- * { key: 'name', value: 'coder' }
- * { key: 'age', value: 18 }
- * { key: 'info', value: [ 'abc', 'acb', 'ope' ] }
- */
- }
很多原生对象已经实现了可迭代协议,会生成一个迭代器对象,例如 :
String、Array、Map、Set、arguments对象、NodeList集合
- // 数组
- const names = ['abc', 'cba', 'nba'];
- // 1. 使用[Symbol.iterator]方法
- const namesIterator = names[Symbol.iterator]();
- console.log(namesIterator.next()); // {value: 'abc', done: false}
- console.log(namesIterator.next()); // {value: 'cba', done: false}
- console.log(namesIterator.next()); // {value: 'nba', done: false}
- console.log(namesIterator.next()); // {value: undefined, done: true}
- // 2. 使用for..of..
- for (const name of names) {
- console.log(name); // abc cba nba
- }
- // Set
- const set = new Set(['abc', 'cba', 'nba']);
- // 1. 使用[Symbol.iterator]方法
- const setIterator = set[Symbol.iterator]();
- console.log(setIterator.next()); // {value: 'abc', done: false}
- console.log(setIterator.next()); // {value: 'cba', done: false}
- console.log(setIterator.next()); // {value: 'nba', done: false}
- console.log(setIterator.next()); // {value: undefined, done: true}
- // 2. 使用for..of..
- for (const item of set) {
- console.log(item); // abc cba nba
- }
- // arguments
- function foo() {
- const arguIterator = arguments[Symbol.iterator]();
- // 1. 使用[Symbol.iterator]方法
- console.log(arguIterator.next()); // {value: 111, done: false}
- console.log(arguIterator.next()); // {value: 222, done: false}
- console.log(arguIterator.next()); // {value: 333, done: false}
- console.log(arguIterator.next()); // {value: undefined, done: true}
- // 2. 使用for..of..
- for (const arg of arguments) {
- console.log(arg); // 111 222 333
- }
- }
- foo(111, 222, 333);
JavaScript中语法:
for ...of、展开语法、yield*、解构赋值、...
注 : 对象可以在对象中展开,不是因为可迭代对象,是js引擎专门加上的,以前是只有可迭代对象才能展开
创建一些对象时:
new Map([Iterable])、new WeakMap([iterable])、new Set([iterable])、new WeakSet([iterable])、...
一些方法的调用:
Promise.all(iterable)、Promise.race(iterable)、Array.from(iterable)、...
都是传入的可迭代对象,也就是说,只要是可迭代对象,这些场景都能使用
- // 1. 使得info对象编程可迭代对象
- const info = {
- name: 'coder',
- age: 18,
- height: 1.88,
- // 2. 设定返回的值为对象的value值
- [Symbol.iterator]: function () {
- const values = Object.values(this);
- let index = 0;
- const iterator = {
- next: function () {
- if (index < values.length) {
- return { done: false, value: values[index++] };
- } else {
- return { done: true };
- }
- }
- };
- return iterator;
- }
- };
- function foo(arg1, arg2, arg3) {
- console.log(arg1, arg2, arg3); // coder 18 1.88
- }
-
- // 3. 展开运算符可以展开可迭代对象,这里自定义了
- foo(...info);
- // set中, 也是传入的可迭代对象
-
- // 1. 传入数组,因为数组是可迭代对象
- const set = new Set(['aaa', 'bbb', 'ccc']);
- console.log(set); // Set(3) {'aaa', 'bbb', 'ccc'}
- // 2. 传入字符串,因为字符是可迭代对象
- const set2 = new Set('abc');
- console.log(set2); // Set(3) {'a', 'b', 'c'}
- // 3. 传入自定义的可迭代对象
- const set3 = new Set(info);
- console.log(set3); // Set(3) {'coder', 18, 1.88}
- // 3.Promise.all中, 也是传入的可迭代对象
- const p1 = Promise.resolve('aaa');
- const p2 = Promise.resolve('bbb');
- const p3 = Promise.resolve('ccc');
- const pSet = new Set();
- pSet.add(p1);
- pSet.add(p2);
- pSet.add(p3);
- // 传入set对象,因为set也是可迭代对象
- Promise.all(pSet).then((res) => {
- console.log(res); // ['aaa', 'bbb', 'ccc']
- });
使得类创建出来的对象默认是可迭代
- // 1. 定义一个类
- class Person {
- constructor(name, age, height) {
- this.name = name;
- this.age = age;
- this.height = height;
- }
- // 2. 定义[Symbol.iterator]实例方法,让所有实例都能访问
- [Symbol.iterator]() {
- let index = 0;
- const entries = Object.entries(this);
- return {
- next() {
- if (index < entries.length) {
- const [key, value] = entries[index++];
- return { done: false, value: { key, value } };
- } else {
- return { done: true };
- }
- }
- };
- }
- }
-
- // 3. 创建实例对象,且生成的对象都为可迭代对象
- const p1 = new Person('coder', 18, 1.88);
- const p2 = new Person('star', 16, 1.66);
-
- for (const item of p1) {
- /**
- * { key: 'name', value: 'coder' }
- * { key: 'age', value: 18 }
- * { key: 'height', value: 1.88 }
- */
- console.log(item);
- }
-
- for (const item of p2) {
- /**
- * { key: 'name', value: 'star' }
- * { key: 'age', value: 16 }
- * { key: 'height', value: 1.66 }
- */
- console.log(item);
- }
迭代器在某些情况下会在没有完全迭代的情况下中断 :
- // 1. 定义一个类
- class Person {
- constructor(name, age, height) {
- this.name = name;
- this.age = age;
- this.height = height;
- }
- // 2. 定义[Symbol.iterator]实例方法,让所有实例都能访问
- [Symbol.iterator]() {
- let index = 0;
- const entries = Object.entries(this);
- return {
- next() {
- if (index < entries.length) {
- const [key, value] = entries[index++];
- return { done: false, value: { key, value } };
- } else {
- return { done: true };
- }
- },
- // 3. 如果中断了,回调用该方法
- return() {
- console.log('中断了');
- // 记得返回一个对象,否则会报错。迭代器都是要返回一个对象的
- return { done: true };
- }
- };
- }
- }
-
- // 4. 创建实例对象,且生成的对象都为可迭代对象
- const p = new Person('coder', 18, 1.88);
-
- for (const { key, value } of p) {
- console.log(value); // coder 18
- if (value === 18) {
- break; // 中断了
- }
- }
生成器 : ES6中新增的一种函数控制、使用的方案,它可以让我们更加灵活的控制函数什么时候继续执行、暂停执行等
生成器函数也是一个函数,但是和普通的函数有一些区别:
- /*
- 生成器函数:
- 1.function后面会跟上符号: *
- 2.代码的执行可以被yield控制
- 3.生成器函数默认在执行时, 返回一个生成器对象
- * 要想执行函数内部的代码, 需要生成器对象, 调用它的next操作
- * 当遇到yield时, 就会中断执行
- */
-
- // 1.定义了一个生成器函数
- function* foo() {
- console.log(111);
- console.log(222);
- yield;
- console.log(333);
- console.log(444);
- yield;
- console.log(555);
- console.log(666);
- yield;
- console.log('函数结束运行');
- }
-
- // 2.调用生成器函数, 返回一个 生成器对象
- const generator = foo();
- // 3. 调用next方法
-
- // 执行到第一个yield,并且暂停
- generator.next(); // 111 222
- // 执行到第二个yield,并且暂停
- generator.next(); // 333 444
- // 执行到第三个yield,并且暂停
- generator.next(); // 555 666
- // 执行到第三个yield,并且暂停剩下的函数
- generator.next(); // '函数结束运行'
- // 1.定义了一个生成器函数
- function* foo() {
- console.log(111);
- console.log(222);
- // 定义返回值
- yield 'first';
- console.log(333);
- console.log(444);
- yield ['secode'];
- console.log(555);
- console.log(666);
- yield { key: 'three' };
- console.log('函数结束运行');
- }
-
- // 2.调用生成器函数, 返回一个 生成器对象
- const generator = foo();
- // 3. 调用next方法
- console.log(generator.next());
- console.log(generator.next());
- console.log(generator.next());
- console.log(generator.next());
-
- /**
- * 打印结果
- * 111
- 222
- { value: 'first', done: false }
- 333
- 444
- { value: [ 'secode' ], done: false }
- 555
- 666
- { value: { key: 'three' }, done: false }
- '函数结束运行'
- { value: undefined, done: true }
- */
- // 1.定义了一个生成器函数
- function* foo() {
- console.log(111);
- console.log(222);
- // 定义返回值
- yield 'first';
- console.log(333);
- console.log(444);
- // 遇到return,直接返回
- return ['secode'];
- console.log(555);
- console.log(666);
- yield { key: 'three' };
- console.log('函数结束运行');
- }
-
- // 2.调用生成器函数, 返回一个 生成器对象
- const generator = foo();
- // 3. 调用next方法
- console.log(generator.next());
- console.log(generator.next());
- console.log(generator.next());
- console.log(generator.next());
-
- /**
- * 打印结果
- * 111
- 222
- { value: 'first', done: false }
- 333
- 444
- { value: [ 'secode' ], done: true }
- { value: undefined, done: true }
- { value: undefined, done: true }
- */
在调用next函数的时候,可以给它传递参数,那么这个参数会作为上一个yield语句的返回值
注意:也就是说我们是为本次的函数代码块执行提供了一个值
- // 1.定义了一个生成器函数
- function* foo(msg1) {
- console.log(111, msg1);
- console.log(222, msg1);
- // 这里接受第二个next
- const msg2 = yield 'first';
- console.log(333, msg2);
- console.log(444, msg2);
- // 这里接受第三个next
- const msg3 = yield ['secode'];
- console.log(555, msg3);
- console.log(666, msg3);
- // 这里接受第四个next
- const msg4 = yield { key: 'three' };
- console.log('函数结束运行', msg4);
- }
-
- // 1. 第一次传的参数,一般写在这
- const generator = foo('next1');
-
- console.log(generator.next());
- // 2. 第二次传的参数,注意,接受的地方为第一个yield
- console.log(generator.next('next2'));
- console.log(generator.next('next3'));
- console.log(generator.next('next4'));
-
- /**
- * 111 next1
- 222 next1
- { value: 'first', done: false }
- 333 next2
- 444 next2
- { value: [ 'secode' ], done: false }
- 555 next3
- 666 next3
- { value: { key: 'three' }, done: false }
- 函数结束运行 next4
- { value: undefined, done: true }
- */
- function* foo(name1) {
- console.log('执行内部代码:1111', name1);
- console.log('执行内部代码:2222', name1);
- const name2 = yield 'aaaa';
- console.log('执行内部代码:3333', name2);
- console.log('执行内部代码:4444', name2);
- const name3 = yield 'bbbb';
- // return "bbbb"
- console.log('执行内部代码:5555', name3);
- console.log('执行内部代码:6666', name3);
- yield 'cccc';
-
- console.log('最后一次执行');
- return undefined;
- }
-
- const generator = foo('next1');
-
- // generator.return提前结束函数
- console.log(generator.next());
- console.log(generator.return('next2'));
- // done为true,不会执行内部的代码了
- console.log('-------------------');
- console.log(generator.next('next3'));
- console.log(generator.next('next4'));
- /**
- *
- * 执行内部代码:1111 next1
- 执行内部代码:2222 next1
- {value: 'aaaa', done: false}
- {value: 'next2', done: true}
- -------------------
- {value: undefined, done: true}
- {value: undefined, done: true}
- *
- */
- function* foo(name1) {
- console.log('执行内部代码:1111', name1);
- console.log('执行内部代码:2222', name1);
- const name2 = yield 'aaaa';
- console.log('执行内部代码:3333', name2);
- console.log('执行内部代码:4444', name2);
- const name3 = yield 'bbbb';
- // return "bbbb"
- console.log('执行内部代码:5555', name3);
- console.log('执行内部代码:6666', name3);
- yield 'cccc';
-
- console.log('最后一次执行');
- return undefined;
- }
-
- const generator = foo('next1');
- // generator.throw向函数抛出一个异常
- console.log(generator.next());
- console.log(generator.throw(new Error('next2 throw error')));
- // 也立即终止了
- console.log('-------------------');
- console.log(generator.next('next3'));
- console.log(generator.next('next4'));
-
- /**
- * 执行内部代码:1111 next1
- 执行内部代码:2222 next1
- {value: 'aaaa', done: false}
- 报错,这里没有捕获,可以用try catch
- */
生成器是一种特殊的迭代器,那么在某些情况下可以使用生成器来替代迭代器
- const arr = ['a', 'b', 'c', 'd'];
- const nums = [11, 22, 33];
-
- // 1. 创建生成器函数
- function* createArrayIterator(arr) {
- for (let i = 0; i < arr.length; i++) {
- // 完美!
- yield arr[i];
- }
- }
-
- // 2. 创建生成器,生成器就是一个特殊的迭代器
- const arrIterator = createArrayIterator(arr);
- console.log(arrIterator.next()); // { done: false, value: 'a' }
- console.log(arrIterator.next()); // { done: false, value: 'b' }
- console.log(arrIterator.next()); // { done: false, value: 'c' }
- console.log(arrIterator.next()); // { done: false, value: 'd' }
- console.log(arrIterator.next()); // { done: true, value: undefined }
- console.log(arrIterator.next()); // { done: true, value: undefined }
-
- // 3. 创建生成器,生成器就是一个特殊的迭代器
- const numsIterator = createArrayIterator(nums);
- console.log(numsIterator.next()); // { done: false, value: 11 }
- console.log(numsIterator.next()); // { done: false, value: 22 }
- console.log(numsIterator.next()); // { done: false, value: 33 }
- console.log(numsIterator.next()); // { done: true, value: undefined }
- console.log(numsIterator.next()); // { done: true, value: undefined }
- console.log(numsIterator.next()); // { done: true, value: undefined }
- // [3, 9)
- function* createRangeGenerator(start, end) {
- for (let i = start; i < end; i++) {
- yield i;
- }
- }
-
- const rangeGen = createRangeGenerator(3, 9);
- console.log(rangeGen.next()); // {value: 3, done: false}
- console.log(rangeGen.next()); // {value: 4, done: false}
- console.log(rangeGen.next()); // {value: 5, done: false}
- console.log(rangeGen.next()); // {value: 6, done: false}
- console.log(rangeGen.next()); // {value: 7, done: false}
- console.log(rangeGen.next()); // {value: 8, done: false}
- console.log(rangeGen.next()); // {value: undefined, done: true}
还可以使用yield*来生产一个可迭代对象
这个时候的 yield* 是一种yield的语法糖,只不过会依次迭代这个可迭代对象,每次迭代其中的一个值
- const arr = ['a', 'b', 'c', 'd'];
- const nums = [11, 22, 33];
-
- // 1. 创建生成器函数
- function* createArrayIterator(arr) {
- // 一行代码搞定
- yield* arr;
- }
-
- // 2. 创建生成器,生成器就是一个特殊的迭代器
- const arrIterator = createArrayIterator(arr);
- console.log(arrIterator.next()); // { done: false, value: 'a' }
- console.log(arrIterator.next()); // { done: false, value: 'b' }
- console.log(arrIterator.next()); // { done: false, value: 'c' }
- console.log(arrIterator.next()); // { done: false, value: 'd' }
- console.log(arrIterator.next()); // { done: true, value: undefined }
- console.log(arrIterator.next()); // { done: true, value: undefined }
-
- // 3. 创建生成器,生成器就是一个特殊的迭代器
- const numsIterator = createArrayIterator(nums);
- console.log(numsIterator.next()); // { done: false, value: 11 }
- console.log(numsIterator.next()); // { done: false, value: 22 }
- console.log(numsIterator.next()); // { done: false, value: 33 }
- console.log(numsIterator.next()); // { done: true, value: undefined }
- console.log(numsIterator.next()); // { done: true, value: undefined }
- console.log(numsIterator.next()); // { done: true, value: undefined }
- // 1. 可迭代对象
- const info = {
- name: 'coder',
- age: 18,
- info: [1, 2, 3],
- *[Symbol.iterator]() {
- yield* Object.entries(this);
- }
- };
-
- // 2. 获取生成器对象
- const infoIterator = info[Symbol.iterator]();
- // 3. 调用next方法
- console.log(infoIterator.next()); // { value: [ 'name', 'coder' ], done: false }
- console.log(infoIterator.next()); // { value: [ 'age', 18 ], done: false }
- console.log(infoIterator.next()); // { value: [ 'info', [ 1, 2, 3 ] ], done: false }
- console.log(infoIterator.next()); // { value: undefined, done: true }
- // 1. 定义一个类
- class Person {
- constructor(name, age, height) {
- this.name = name;
- this.age = age;
- this.height = height;
- }
- // 2. 定义[Symbol.iterator]实例方法,让所有实例都能访问
- *[Symbol.iterator]() {
- yield* Object.entries(this);
- }
- }
-
- // 3. 创建实例对象,且生成的对象都为可迭代对象
- const p1 = new Person('coder', 18, 1.88);
- const p2 = new Person('star', 16, 1.66);
-
- for (const [key, value] of p1) {
- /**
- * name coder
- * age 18
- * height 1.88
- */
- console.log(key, value);
- }
-
- for (const [key, value] of p2) {
- /**
- * name star
- * age 16
- * height 1.66
- */
- console.log(key, value);
- }
-
- const p1Iterator = p1[Symbol.iterator]();
- console.log(p1Iterator.next()); // { value: [ 'name', 'coder' ], done: false }
- console.log(p1Iterator.next()); // { value: [ 'age', 18 ], done: false }
- console.log(p1Iterator.next()); // { value: [ 'height', 1.88 ], done: false }
- console.log(p1Iterator.next()); // { value: undefined, done: true }
- console.log(p1Iterator.next()); // { value: undefined, done: true }