Interator和Generator

Posted 还是不会呀

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Interator和Generator相关的知识,希望对你有一定的参考价值。

Iterator

认识迭代器

迭代器:帮助遍历某个数据结构的对象。

一个对象需要成为迭代器需要满足迭代器协议迭代器协议定义了一个产生一系列对象的标准方式,在JS中 这个标准就是next方法。

next方法是一个可以传入零个或者一个参数的函数,这个函数返回一个对象,这个对象包括:

  • done属性:当还没有遍历完成时done的值是 false,当遍历完成时这个值时 true
  • value属性:当前位置上的值,遍历完时对应的值是undefined

迭代器代码

为一个数组写一个迭代器

const names = ["abc", "cba", "nba"];
let index = 0;
const nameIterator = {
  next: function () {
    if (index < names.length) {
      return { done: false, value: names[index++] };
    } else {
      return { done: true, value: undefined };
    }
  },
};

console.log(nameIterator.next());
console.log(nameIterator.next());
console.log(nameIterator.next());
console.log(nameIterator.next());
// { done: false, value: 'abc' }
// { done: false, value: 'cba' }
// { done: false, value: 'nba' }
// { done: true, value: undefined }

创建数组迭代器的工厂函数

function createArrayIterator(arr) {
  let index = 0;
  return {
    next: function () {
      if (index < arr.length) {
        return { done: false, value: arr[index++] };
      } else {
        return { done: true, value: undefined };
      }
    },
  };
}
const nums = [1, 2, 3];
const numsIterator = createArrayIterator(nums);
console.log(numsIterator.next());
console.log(numsIterator.next());
console.log(numsIterator.next());
console.log(numsIterator.next());

认识可迭代对象

可迭代对象也是一个对象。但是 可迭代对象≠迭代器

一个对象符合可迭代协议就可以是一个可迭代对象。可迭代对象需要有@@ iterator方法,在JS代码中表现为Symbol.iterator访问该属性。

Symbol.iterator是一个函数,这个函数的返回值是一个迭代器

可迭代对象代码

这种方式和迭代器代码相比,代码之间的关联度更加紧密了

const info = {
  name: ["abc", "cba", "nba"],
  [Symbol.iterator]: function () {
    let index = 0;
    const that = this;
    return {
      next: function () {
        if (index < that.name.length) {
          return { done: false, value: that.name[index++] };
        } else {
          return { done: true, value: undefined };
        }
      },
    };
  },
};

const infoIterator = info[Symbol.iterator]();

console.log(infoIterator.next());
console.log(infoIterator.next());
console.log(infoIterator.next());
console.log(infoIterator.next());
// { done: false, value: 'abc' }
// { done: false, value: 'cba' }
// { done: false, value: 'nba' }
// { done: true, value: undefined }

内置可迭代对象

// 1、字符串
const message = "message";
console.log(message[Symbol.iterator]); // [Function: [Symbol.iterator]]

// 2、数组
const nums = [1, 2, 3, 4];
console.log(nums[Symbol.iterator]); // [Function: values]

// 3、arguements
function foo(x, y, z) {
  console.log(arguments[Symbol.iterator]);// [Function: values]
}
foo();

// 4、Set(传入的是一个可迭代对象,返回的也是一个可迭代对象)
const set = new Set(message);
console.log(set[Symbol.iterator]);// [Function: values]

// 5、Map(返回的也是一个可迭代对象)
const map = new Map();
console.log(map[Symbol.iterator]);// [Function: entries]

可迭代对象的应用

  • for…of (必须是可迭代对象才能使用for…of)

  • Array.from(iterable | ArrayLike)

  • 数组的展开语法

  • 数组的解构语法

  • Promise类方法

  • 创建Set数据结构

自定义类的可迭代

class Person {
  constructor(name, age, friends) {
    this.name = name;
    this.age = age;
    this.friends = friends;
  }
  makeFriend(name) {
    this.friends.push(name);
  }
  [Symbol.iterator]() {
    let index = 0;
    return {
      next: () => {
        if (index < this.friends.length) {
          return { done: false, value: this.friends[index++] };
        } else {
          return { done: true, value: undefined };
        }
      },
    };
  }
}
const person = new Person("fzb", 21, ["abc", "cba", "hgl"]);
const personIterator = person[Symbol.iterator]();
console.log(personIterator.next());
console.log(personIterator.next());
console.log(personIterator.next());
console.log(personIterator.next());

Generator

生成器的理解

生成器是一个函数,可以控制函数内代码的执行流程。

生成器函数和普通函数的区别

  • 在定义函数的时候,生成器函数需要在function关键字后加*
  • 生成器函数可以控制函数内代码的执行逻辑,但普通函数不行。
  • 生成器函数的返回值是一个迭代器.

生成器函数的执行流程

yield后面跟着的值,将作为 迭代器.next返回对象的value

return后面跟着的值将作为 迭代器.next最后一次返回对象的value值,同时done:true

其实还可以向生成器函数内传参数

next方法内传入的参数在上一个yield内接收

第一个next方法一般不传参数,因为前面也没有yield,要传参数在获取迭代器的时候传入参数就行了

function* foo() {
  console.log("函数内代码开始执行~");

  const num1 = 100;
  console.log("num1:", num1);
  const n = yield num1;
  console.log("我是第二的next内传入的参数:", n); // 我是第二的next内传入的参数: 10

  const num2 = 200;
  console.log("num2:", num2);
  return num2;
}

const iterator = foo();

console.log(iterator.next());
console.log(iterator.next(10));

生成器的其他方法调用

return方法

提前终止生成器函数,返回传入的值

function* foo() {
  console.log("函数内代码开始执行~");

  const num1 = 100;
  console.log("num1:", num1);
  const n = yield num1;
  // 相当于 return n
  console.log("我是第二的next内传入的参数:", n);

  const num2 = 200;
  console.log("num2:", num2);
  yield num2;

  const num3 = 300;
  console.log("num3:", num3);
}

const iterator = foo();

console.log(iterator.next());
console.log(iterator.return(10)); // 在使用return后 相当于传入参数后直接return
console.log(iterator.next());

throw方法

对上一次返回对象的值不满意,抛出错误,并且可以继续执行下面代码

function* foo() {
  console.log("函数内代码开始执行~");

  const num1 = 100;
  console.log("num1:", num1);
  try {
    yield num1;
  } catch (error) {
    console.log(error);
  }

  const num2 = 200;
  console.log("num2:", num2);
  yield num2;

  const num3 = 300;
  console.log("num3:", num3);
}

const iterator = foo();

console.log(iterator.next());
console.log(iterator.throw("error message"));
console.log(iterator.next());

以上是关于Interator和Generator的主要内容,如果未能解决你的问题,请参考以下文章

Interator和Generator

ES6中的Module与Interator

遍历一个Set的方法只有一个:迭代器(interator)

es6 Interator

第二十章-----Interator简单整理

ES6 Interator