一、迭代器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());//2
console.log(t.sayColor());
console.log(t.sayName());