前言
首先要回顾迭代器和生成器的话,心中要有一个概念,迭代器其实可以看成一种规范,类似promise+规范的的东西,迭代器是一个函数,一个符合迭代器规范的函数。
那么这个规范是啥?个人简单的理解就是 迭代器函数返回一个含有next方法的对象,next方法返回一个包含 value done 属性的对象。只要符合这个规范的函数 都可以称之为迭代器。
那么什么是生成器?个人理解就是 function* 其实也是一个函数,只是这个函数比较特殊,该函数返回一个generator对象,该对象也就是上面说说的迭代器函数返回的对象。只是此时function是隐式的返回。而迭代器函数是显式的返回带有next方法的对象。
迭代器
迭代器说明
下面这个例子就是一个迭代器例子,其实迭代器next方法的调用可以看成指针的移动,每调用一次next,指针就移向数据结构中的下一个数据,返回 { value: 值, done: 布尔值(遍历结束没)}。遍历完了后不管调用几次next,都是返回{ value: undefined, done: true }。
var it = makeIterator(['a', 'b']);
it.next() // { value: "a", done: false }
it.next() // { value: "b", done: false }
it.next() // { value: undefined, done: true }
function makeIterator(array) {
var nextIndex = 0;
return {
next: function () {
return nextIndex < array.length ?
{ value: array[nextIndex++], done: false } :
{ value: undefined, done: true };
}
};
}
迭代器接口
其实在JS里已经有很多对象是可迭代的。比如 常用的Array Map Set String,这些类型的实例里都有一个名为Symbol.iterator的接口函数,可直接调用该函数返回迭代器。这些对象不用任何处理就可以被 for...of 循环遍历(可用break),而普通的对象是不能的(除非我们人为的给对象加上Symbol.iterator接口)。
let arr = ['a', 'b', 'c'];
// 可直接调用Symbol.iterator接口
let iter = arr[Symbol.iterator]();
iter.next() // { value: 'a', done: false }
iter.next() // { value: 'b', done: false }
iter.next() // { value: 'c', done: false }
iter.next() // { value: undefined, done: true }
练手题
针对上面说的普通对象是没法被遍历的,那么如何实现 obj={a: '1', b: '2'} let arr = [...obj] 输出 [1, 2]。
其实这题就是考察解构符号,对象不能在数组里面解构。会报错 TypeError: obj is not iterable,那么只要把这个对象添加上Symbol.iterator 接口函数就可以了。
function Valuemaker(obj) {
let index = 0;
return {
next: function () {
if (index < Object.keys(obj).length) {
return { value: obj[Object.keys(obj)[index++]], done: false}
}
return { done: true }
}
}
}
let obj = {a: 1, b: 2, c: 3};
// 让obj拥有Sym接口
obj[Symbol.iterator] = function () {
return Valuemaker(obj);
}
let it = Valuemaker(obj);
生成器
示例说明
生成器其实也是个函数,只是写的方式为 function* 可以生成generator生成对象。函数在调用对象的next方法时才会执行。搭配yield使用。generator需要注意的是在return 的前一个返回值,done就已经变成了true。next(参数)可以传值。作为上一个yield的返回值。
function* helloWorldGenerator() {
yield 'hello';
yield 'world';
return 'ending';
}
var hw = helloWorldGenerator();
hw.next()
// { value: 'hello', done: false }
hw.next()
// { value: 'world', done: false }
hw.next()
// { value: 'ending', done: true }
hw.next()
// { value: undefined, done: true }
练手题
以下输出啥?关键的地方在于 当next(传参)的时候,这个传参相当于上一个yield的返回值,注意如果没有传参的话,yield的返回值一定是undefined
还有要注意的点是由于 next ⽅法的参数表示上⼀个 yield 语句的返回值, 所以第⼀ 次使⽤ next ⽅法时, 不能带有参数。!!!!
function* foo(x) {
var y = 2 * (yield (x + 1));
var z = yield (y / 3);
return (x + y + z);
} v
ar a = foo(5);
a.next() // ?
a.next() // ?
a.next() // ?
var b = foo(5);
b.next() // ?
b.next(12) // ?
b.next(13) // ?
以下输出啥?
function* foo() {
yield 1;
yield 2;
yield 3;
yield 4;
yield 5;
return 6;
}
for(let v of foo()) {
console.log(v);
}
// 1 2 3 4 5
//⼀旦 next ⽅法的返回对象的 done 属性为 true , for...of 循环就会中⽌
用生成器写一个斐波那契函数
function* fibo() {
yield 0;
yield 1;
let [pre, cur] = [0, 1];
for(;;) {
[pre, cur] = [cur, pre + cur];
yield cur;
}
}
let a = fibo();
for (let v of a) {
if (v > 100) break;
console.log(v);
}
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!