ES6学习笔记(第二天)
1.迭代器
迭代器(lterator)是一种接口,为各种不同的数据结果提供统一的访问机制,只要部署了lterator接口,就可以完成遍历操作,es6创造一种新的遍历方式:for…of
原生具备iterator的数据(可以用for…of循环)有:
Array
Argunments
Set
Map
String
TypedArray
NodeList
事例:
var data=['wwh','wxh','cxj']
for(let i in data){
console.log(i)//输出0,1,2
}
for(let i of data){
console.log(i)//输出wwh,wxh,cxj
}
//in对应key,of对应value,在对象中也可以这样用
工作原理:
官方:
先创建一个指针对象,指向当前数据结构的起始位置
第一次调用对象的next方法,指针自动指向数据结构的第一个成员
接下来不断调用next方法,指针一直往后移动,直到指向最后一个成员
每次调用next方法就会返回一个包含value和done属性(是否完成)的对象
自己的理解:
使用data数组里面的Symbol(Symbol.iterator): ƒ values() 这个函数创建了一个对象,这个对象里面的next方法一直访问data里面对应的key/value,每次返回的都是一个对象,里面包含value和done两个属性,访问完后返回value:undefined的对象
事例:
let d=data[Symbol.iterator]()//通过[]调用属性,与.一致,Symbol.iterator是一个属性,这个属性里面是一个函数,最后用()调用这个函数,创建了一个对象
console.log(d)//查看这个对象,里面有一个next()方法
console.log(d.next());//{value: 'wwh', done: false}
console.log(d.next());//{value: 'wxh', done: false}
console.log(d.next());//{value: 'cxj', done: false}
console.log(d.next());//{value: undefined, done:true}
迭代器的应用:自定义遍历方法
案例:
定义一个遍历方法,可以遍历一个对象中数组的所有成员。
//声明一个对象
const data={
name:'airen',
lis:[
'wwh',
'wxh',
'cxj'
],
//自己给某些结构加上iterator接口
[Symbol.iterator](){
//索引变量
let index=0;
//没有这行,this指向return的那个对象,相当于把this的作用域往上提了一层
let _this=this;
return {//返回一个指针对象,即创建一个指针对象
next:function(){ //创建对象的next方法
// 返回一个包含value和done属性(是否完成)的对象
if(index<_this.lis.length){
const result= {value:_this.lis[index],done:false};
index++;
return result;
}else{
return {value:undefined,done:true};
}
}
};
}
}
//自定义遍历这个对象
for(let v of data){
console.log(v);
}
console.log('--------------------')
console.log(data);
// 输出结果
// wwh
// wxh
// cxj
// --------------------
// {name: 'airen', lis: Array(3), Symbol(Symbol。iterator): ƒ}
// lis: (3) ['wwh', 'wxh', 'cxj']
// name: "airen"
// Symbol(Symbol.iterator): ƒ [Symbol.iterator]()
// [[Prototype]]: Object
2.生成器
生成器就是一个特殊的函数,是异步编程新的解决方案。它的结构不是直接输出,而是要通过next()来控制
//定义方式 *
function * fun(){
console.log('wwh');
}
let a=fun();
// console.log(a);//输出一个迭代器对象(有next方法)
a.next();//输出wwh
function * fun(){
console.log('wwh');
//yield 分割代码块,一个可以分为两个
yield '暂停';
console.log('wxh');
yield '暂停';
console.log('cxj');
}
let a=fun();
console.log(a);//输出一个迭代器对象(有next方法)
a.next();//输出wwh
a.next();//输出wxh
a.next();//输出cxj
//利用for...of可以输出yield的内容
for(let v of fun()){
console.log(v)
}
// 输出内容:
// wwh
// 暂停
// wxh
// 暂停
// cxj
//原因:
// yield后面自定义的值在next返回对象的value里面
生成器函数的参数传递
function * fun(arg){
console.log(arg);//输出aaa
let one=yield 111;
console.log(one);//输出bbb
let two=yield 222;
console.log(two);//输出ccc
let three=yield 333;
console.log(three);//输出ddd
}
let a=fun('aaa');
console.log(a.next());//第一次调用next
//next方法可以传入实参
//第二次调用next的实参将作为第一个yield的整体返回结果
console.log(a.next('bbb'))//输出{value: 222, done: false}
console.log(a.next('ccc'))
console.log(a.next('ddd'))
作为异步编程的新方法
//需求:1s后输出111,2s后输出222,3s后输出333
//第一种实现方式:
// setTimeout(() => {
// console.log(111);
// setTimeout(() => {
// console.log(222);
// setTimeout(() => {
// console.log(333); //如果有很多个的化会一直推进,可能会超出显示器范围,不好维护和操作
// }, 3000);
// }, 2000);
// }, 1000);
// 第二种实现方式:
function one(){
setTimeout(()=>{
console.log(111);
a.next(); //定时器运行完调用下一个,实现了异步编程
//不会推进,一直是这样的往下一列,方便观看和操作、维护
},1000)
}
function two(){
setTimeout(()=>{
console.log(222);
a.next();
},2000)
}
function three(){
setTimeout(()=>{
console.log(333);
a.next();
},3000)
}
function *fun(){
yield one();
yield two();
yield three();
}
//调用生成器函数
let a=fun();
a.next();
练习:
需求:模拟获取,分别一秒后打印出用户信息、订单信息、商品信息
function getuser(){
setTimeout(()=>{
let data='用户信息' //一定要有延时器否则会报错
it.next(data) //第二个调用的next(),它的实参会被当成第一个yield的返回值
},1000)
}
function getorder(){
setTimeout(()=>{
let data='订单信息'
it.next(data) //第三个调用的next(),它的实参会被当成第二个yield的返回值
},1000)
}
function getgoods(){
setTimeout(()=>{
let data='商品信息'
it.next(data) //第四个调用的next(),它的实参会被当成第三个yield的返回值
},1000)
}
function * get(){
let user=yield getuser();
console.log(user);
let order=yield getorder();
console.log(order);
let good=yield getgoods();
console.log(good);
}
let it=get() //返回一个对象,用it接受
it.next() //it属性里有一个next(),第一个调用的next()
3.Promise
它是es6中异步编程的新的解决方案。相当于一个构造函数、
//实例化Promise对象
//对象的状态只有三种初始化、成功、失败
const p= new Promise((resolve,reject)=>{
//如果成功获取数据,就调用resolve
let data='数据库中的数据';
resolve(data); //p状态变为成功
//如果失败就调用reject
let err='数据库读取失败';
reject(err);//p状态变为失败
})
p.then(//调用then方法
function(value){//p状态变为成功后then会调用第一个回调函数
console.log(value);
},function(err){//p状态变为失败后then会调用第二个回调函数
console.log(err);
}
)
事例:读取同级目录下的wenjian.md里面的内容(道阻且长,不行不至。)
//利用node.js的fs模块进行文件操作,演示promise
//这是之前的做法
const fs =require('fs')
fs.readFile('./wenjian.md',(err,data)=>{
if(err) throw err
console.log(data.toString());
})
//这是现在的做法
const p= new Promise((resolve,reject)=>{
fs.readFile('./wenjian.md',(err,data)=>{
//如果失败就调用reject
if(err) throw reject(err)
//如果成功获取数据,就调用resolve
resolve(data);
})
})
p.then(//调用then方法
function(value){//p状态变为成功后then会调用第一个回调函数
//利用toString()转化buffer为字符串
console.log(value.toString());
},function(err){//p状态变为失败后then会调用第二个回调函数
console.error(err);//红色报错
}
)
Promise.prototype.then
const p= new Promise((resolve,reject)=>{
//如果成功获取数据,就调用resolve
let data='数据库中的数据';
resolve(data); //p状态变为成功
//如果失败就调用reject
let err='数据库读取失败';
reject(err);//p状态变为失败
})
const result=p.then(//调用then方法
function(value){//p状态变为成功后then会调用第一个回调函数
console.log(value);
//1.非promise
//return 123,result里面的值就是123
//2.promise
//return 123,result里面的值就是123
},function(err){//p状态变为失败后then会调用第二个回调函数
console.warn(err);//黄色警告
}
)
console.log(result)//then返回的也是一个promise的对象
// 对象状态由then函数的执行结果决定
//1.返回的是非promise类型的数据,则result对象状态为成功,且对象的value就是then函数返回的值;
//2. 如果是promise对象,则result状态由返回的promise对象的状态决定,值同上
catch方法
用来指定promise对象失败的回调
const p=new Promise((resolve,reject)=>{
//设置p对象的状态为失败,并设置失败的值
reject('出错了')
})
//这是第一种指定失败的方法:用then的第二个函数
// p.then(function(value){},function(reason){
// console.error(reason)
// })
//第二种:用catch方法
p.catch(function(reason){
console.error(reason)
})
es6中的promise就学到这里,详细请看专门的promise教程。