一、迭代器Iterator
迭代器是访问数据的一个接口,是用于遍历数据结构的一个指针,迭代器就是遍历器
const items=['one','two','three'];//创建新的迭代器const it=items[Symbol.iterator]();console.log(it.next());
done:返回false表示遍历继续,返回true表示遍历完成
二、生成器Generator
1.generator
generator函数可以通过yield关键字将函数挂起来(只能在函数内部使用)。
它跟普通函数的区别是,他得在function后面加*,调用该函数将会返回一个遍历器对象
generator函数是分段执行的,遇到yield就暂停执行,而next()是恢复执行,把你上一个结果给你返回出来
function* func(){console.log('start');const x=yield '2';console.log('continue'+x);const y=yield '3';console.log('continue'+y);console.log(x+y);return x+y;}const fn=func();console.log(fn.next());console.log(fn.next(2));console.log(fn.next(3));console.log(fn.next());
x它不是yield的返回值,它是当next调用,恢复当前yield传入的实参
(1)遇到yield表达式,就暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回的对象的value属性值。
(2)下一次调用next方法时,再继续往下执行,直到遇到下一个yield表达式。
(3)如果没有再遇到新的yield表达式,就一直运行到函数结束,直到return语句为止,并将return语句后面的表达式的值,作为返回的对象的value属性值。
(4)如果该函数没有return语句,则返回的对象的value属性值为undefined。
所以遇到第一个next的时候,start先输出,然后直接到了第一个yield 2,直接输出2
第二个next,传入了实参2,被x接收,输出continue2,又遇到了yield,直接输出后面的3
第三个next,传入了实参3,被y接收,后面输出x加y为5,然后直接ruturn了5(ruturn输出的效果和yield一样{}
最后的next后面都没有东西了,输出undefined done完成
function* foo(x) {var y = 2 * (yield (x + 1));var z = yield (y / 3);return (x + y + z);
}var a = foo(5);
a.next() // Object{value:6, done:false}
a.next() // Object{value:NaN, done:false}
a.next() // Object{value:NaN, done:true} var b = foo(5);
b.next() // { value:6, done:false }
b.next(12) // { value:8, done:false }
b.next(13) // { value:42, done:true }
再来一个例子,就是每次返回的时候都是yield后面的值,传参数的时候都是给上一个yield,比如说y=2*yield、、、,传12的时候就是2*12
再比如传13的时候就是z=yield、、、,就是z=13
function* dataConsumer() {console.log('Started');console.log(`1. ${yield}`);console.log(`2. ${yield}`);return 'result';
}let genObj = dataConsumer();
genObj.next();
// Started
genObj.next('a')
// 1. a
genObj.next('b')
// 2. b
yield每次后面都没有值,所以没有返回{}啥的
2.使用场景:
(1)为不具备iterator 接口的对象提供遍历操作
之前说有Symbol.iterator接口的就可以进行遍历,那么没有这个接口的怎么进行遍历呢?
function* func(obj){//来构建一个让它有接口用const ks=Object.keys(obj);//获取对象当中所有的k保存到数组[name,age]for(const k of ks){yield [k,obj[ks]];}}const obj={name:'ttt',age:18}//这个对象就是一个没有iterator接口的对象obj[Symbol.iterator]=func;console.log(obj);for (let [key, value] of o[Symbol.iterator](o)) { console.log(`${key}:${value}`); //name:ttt age:18
}
以上代码可以让一个没有iterator接口的对象实现遍历
弹幕说学了ajax再来看,先放一下之后再回来看
(2)让异步代码同步化
定义三个函数:加载中、加载完成、界面隐藏
如果直接调用的话,页面加载完成会最后出现,因为它是个异步
用yield将showData函数卡住,进行showData,然后在showData加了个next去输出。
function loadUI() {console.log('页面加载中Loading……');
}function showData() {setTimeout(() => {console.log('页面加载完成');genLoad.next(); //2.页面加载完成后就立即隐藏}, 1000);
}function hideUI() {console.log('页面隐藏啦');
}function* load() {loadUI();yield showData();hideUI();
}let genLoad = load();
genLoad.next(); //1.加载页面,加载完成的时候停止
三、类的用法
promise和async打算学完ajax之后再返回来好好总结,先不往脑子里灌了
class Sum{constructor(x,y){this.x=x;this.y=y;}add(){console.log(this.x+this.y) ;}}var a=new Sum(1,4);a.add();
类似java写法,class封装一个类,constructor()方法是默认加进去的,不写也默认会有,通过new生成对象实例的时候会自动调用这个方法。
add()函数前面不需要再加function。
四、类的继承
class Animal{constructor(name,age){this.name=name;this.age=age;}sayName(){return this.name;}sayAge(){return this.age;}}
有一个animal的类,我还想写一个dog类,包括名字年龄和颜色,其中年龄和颜色Animal都有,咱们就可以直接继承过来
class Dog extends Animal{constructor(name,age,color){super(name,age);//要继承的this.color=color;}}let t=new Dog('hh',2,'yellow');console.log(t);console.log(t.sayAge());//2
不仅可以继承属性,还能继承方法
class Dog extends Animal{//extends继承constructor(name,age,color){super(name,age);//super使用继承来的方法this.color=color;}sayColor(){//自己的方法return `${this.age}是${this.name}`;}//重写父亲的方法sayName(){return super.sayName();}}let t=new Dog('hh',2,'yellow');console.log(t.sayAge());//2console.log(t.sayColor());console.log(t.sayName());