es6 迭代器和生成器这里写自定义目录标题
迭代器
1.什么是迭代?
将数据按照一定的顺序依次取出的过程叫迭代
迭代能将数据依次取出但是不能保证数据全部取出,也不能确定取出的个数
2.什么是迭代器?
对迭代过程的封装对象。
迭代器拥拥有获取下一个数据的功能 在返回的数据中存在有数据状态,判断是否可以继续向下继续迭代。
3.js中规定的迭代器
js中规定 一个对象中 含有next方法 并且这个next方法返回一个对象 那么我们就认为这个对象为迭代器
迭代器(对象)
var obj = {
next() {
// 用于获取下一个值
return {
// 返回的数据
value : "测试",
// 判断是否继续
done : false
}
}
}
自定义的迭代器(数组)
接下来我们来写一个自定义的迭代器(数组)
let arr = [1,2,3,4];
// isiterator(迭代器)
const isiterator = {
// 声明变量让它从0开始迭代
num : 0,
next() {
var result = {
value : arr[this.num],
// 设置迭代状态 (是否继续)
done : this.num >= arr.length
}
this.num++;
return result;
}
}
console.log(isiterator);
// 调用next每次取出对应的状态和值
console.log(isiterator.next());
每调用一次就会取出一个值,在这里return运用了闭包的原理
试着封装一下自定义数组的迭代器
function isiterator(arr) {
// 声明一个变量让它从0开始迭代
let num = 0;
return {
next() {
var result = {
value: arr[num],
// 设置迭代状态 (判断是否继续)
done: num >= arr.length
}
num++;
return result;
}
}
}
自定义斐波拉契
接着我们来封装个经典的斐波拉契
斐波拉契主要数据排列为:1,1,2,3,5…
即除了第一个和第二个为1以外,后面的为前两个之和
function createFeiboIter() {
// 定义数组初始值
let a = 1;
let b = 1;
// 记录当前位置
let num = 1;
return {
next() {
let value;
if (num <= 2) {
value = 1;
} else {
value = a + b;
}
var res = {
value,
da: false // 因为斐波拉契没有极限值所以返回一直为Flase即可以持续继续
}
// 初始值重新赋予
a = b;
b = res.value;
num++;
return res;
}
}
}
var iterator = createFeiboIter();
console.log(iterator.next().value); // 1
console.log(iterator.next().value); // 1
console.log(iterator.next().value); // 2
console.log(iterator.next().value); // 3
console.log(iterator.next().value);//5
结果如图:
数组的迭代器
// 在ES6里面 对象具有知名符号Symbol.iterator这个属性,这个对象就可以进行迭代
let arr = arr[Symbol.iterator]();
对象设置迭代器
for of方法
数组可以直接用for of便利
普通和对象里面没有iterator接口 所以无法使用for-of进行遍历
类数组对象也可以进行遍历
对象设置迭代器
var obj = {
a : 1,
b : 2,
c : 3,
//让其可以使用for of方法
[Symbol.iterator] () {
// 拿到对象所有的键名
const keys = Object.keys(this);
let i = 0
// 设置迭代器
return {
next : () => {
const propName = keys[i];
const propValue = this[propName];
var result = {
value : {
propName,
propValue
},
done : i++ >= keys.length
}
return result;
}
}
}
}
生成器(generator)
什么是generator函数?
是一种ES6里面提供的一种方法 他是yield标识符和next方法调用 作用是可以是函数分段调用
怎么使用生成器?
function* love() {
yield "1";
yield "2";
yield "3";
return "over"
}
var loves = love();
console.log(loves.next());
console.log(loves.next());
console.log(loves.next());
console.log(loves.next());
console.log(loves.next());
输出为:
调用next方法之后的逻辑 :
1.当函数调用next方法之后 在函数内部遇到了yield关键字 函数就会暂停执行 next方法的返回值就是yeild 后面接的数据
2.当我们再次调用next方法时 就会从当前暂停的位置继续往下走 直到遇到下一个yield
3.运行到最后 没有yield关键字 就会一直往后执行 直到遇到return 关键字 返回的是return后面的值 并且状态变成true
4.最后没有遇到return 返回值为undefined 状态值为true
generator函数的特性 :
- generator函数是分步执行的 以yield 为标志 表示函数暂停执行 通过调用next方法恢复函数执行
- generator函数的写法跟普通函数有区别 在function关键字和函数名之前加一个* 通常情况下 *紧挨着function写
- generator函数直接调用 是不会执行函数体的 而是要调用next方法 才能往下执行
- generator函数调用之后 返回的值是一个iterator对象 只有调用next方法 才会迭代 进入下一个状态
生成器 : 生成器指的是 通过构造函数Generator创建出的生成器对象 让函数可以分布执行 生成器也是一个迭代器 同时也是一个可以迭代的对象
Async和 * 不能同时使用
下面我们来看看数组的生成器
var arr = [15, 16, 17, 19];
function* createGenerator(arr) {
for(const item of arr) {
yield item;
}
}
const iter = createGenerator(arr);
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
结果为:
下面我们在看看生成器里面调用另外一个生成器
function* f1() {
yield 1;
yield 2;
}
function* f2() {
yield* f1(); // 在生成器内部调用其他的生成器 一定要在yield 后面加上*
yield 4;
// return 方法调用之后 就会提前结束生成器函数 整个迭代过程提前结束
// return 9;
// 可以在生成器内部抛出一个错误
// throw 8;
yield 5;
yield 6;
}
const gener = f2();
console.log(gener.next());
console.log(gener.next());
console.log(gener.next());
console.log(gener.next());
console.log(gener.next());
console.log(gener.next());
结果为: