迭代器
迭代器(lterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署lterator接口,就可以完成遍历操作。
ES6迭代器的使用
- ES6创造了一种新的遍历命令
for...of 循环,lterator接口主要供 for...of 消费 - 原生具备iterator接口的数据(可用for of遍历):
- Array
- Arguments
- Set
- Map
- String
- TypedArray
- NodeList
具备iterator接口就是指具有 Symbol.iterator 这个属性
eg:
const xiyou =['唐僧','孙悟空','猪八戒','沙僧']
for(let v of xiyou){
console.log(v)
}
for(let v in xiyou){
console.log(v)
}
console.log(xiyou)
输出:
ES6迭代器的原理
数组之所以能够使用迭代器遍历是因为数组中有 Symbol.iterator 这个属性,他的值是一个函数。 获取该函数
const xiyou =['唐僧','孙悟空','猪八戒','沙僧']
let iterator = xiyou[Symbol.iterator]()
console.log(iterator)
有next方法。
迭代器工作原理:
- 第一次调用对象的next方法,指针自动指向数据结构的第一个成员
- 接下来不断调用next方法,指针一直往后移动,直到指向最后一个成员
- 每调用next方法返回一个包含value和 done属性的对象
即迭代器的实现原理就是:
const xiyou =['唐僧','孙悟空','猪八戒','沙僧']
let iterator = xiyou[Symbol.iterator]()
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
输出:
迭代器的应用——自定义遍历数据
如果想要便利的对象没有Symbol.iterator 属性,可以自定义该属性进行遍历 eg:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<script>
const banji = {
name:'终极一班',
stus:[
'xiaoming',
'xiaohong',
'xiaoli',
'xiaozhang'
],
[Symbol.iterator](){
let index = 0;
let _this = this;
return {
next:function(){
if(index <_this.stus.length){
const result = {value:_this.stus[index],done:false}
index++;
return result
}else{
return {value:undefined,done:true}
}
}
}
}
}
for( let v of banji){
console.log(v)
}
</script>
</body>
</html>
生成器
生成器是一个函数,生成器函数是ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同。 之前实现异步编程使用的都是回调函数(回调函数:我们编写的函数,浏览器调用)。
生成器函数
声明格式
function * 函数名(){
}
eg:
function * gen(){
console.log('hello generator')
}
console.log(gen())
输出: 没有输出hello generator,并且具有next方法,这是一个迭代器函数
调用格式
所以正确的调用方式:(调用next方法)
function * gen(){
console.log('hello generator')
}
let iterator = gen()
iterator.next()
输出:
yield
yield是函数代码的分隔符,生成器函数中可以使用yield来分隔函数。 这时调用一个iterator.next()就执行一段被yield分割的代码。
eg:
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<script>
function * gen(){
console.log('一只没有耳朵')
yield '1';
console.log('一只没有尾巴')
yield '2';
console.log('真奇怪')
yield '3';
console.log('真奇怪')
}
let iterator = gen()
iterator.next()
iterator.next()
iterator.next()
iterator.next()
</script>
</body>
</html>
执行如下语句:
let iterator = gen()
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
输出: 发现这是一个迭代器可以直接使用for of:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<script>
function * gen(){
console.log('一只没有耳朵')
yield '1';
console.log('一只没有尾巴')
yield '2';
console.log('真奇怪')
yield '3';
console.log('真奇怪')
}
for(let v of gen()){
}
console.log('--------------------------')
for(let v of gen()){
console.log(v)
}
</script>
</body>
</html>
生成器的函数参数
可以直接给生成器函数传参, next()方法可以传入实参,该实参将作为上一个yield的返回结果. EG:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function * gen(arg){
console.log(arg)
let first = yield 111
console.log(first)
let second = yield 222
console.log(second)
let third = yield 333
console.log(third)
}
let iterator = gen('AAA')
console.log(iterator.next())
console.log(iterator.next('BBB'))
console.log(iterator.next('CCC'))
console.log(iterator.next('DDD'))
</script>
</body>
</html>
输出:
生成器的异步编程
js是一个单线程的,所以很多js操作都是异步的,如: 文件操作、网络操作(ajax, request)、数据库操作
定时器异步操作
需求:1s后控制台输出111 ,2s后输出 222,3s后输出333
<script>
setTimeout(()=>{
console.log(111);
setTimeout(()=>{
console.log(222);
setTimeout(()=>{
console.log(333);
},3000)
},2000)
},1000)
</script>
(箭头函数时回调函数的一种) 通过回调里面套回调,不停的回调来实现异步操作,这就出现了回调地狱。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function one(){
setTimeout(()=>{
console.log(111)
iterator.next()
},1000)
}
function two(){
setTimeout(()=>{
console.log(222)
iterator.next()
},2000)
}
function three(){
setTimeout(()=>{
console.log(333)
iterator.next()
},3000)
}
function * gen(){
yield one()
yield two()
yield three()
}
let iterator=gen()
iterator.next()
</script>
</body>
</html>
异步获取数据
需求:依次获取用户数据、订单数据、商品数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function getUsers(){
setTimeout(()=>{
let data = '用户数据'
iterator.next(data)
},1000)
}
function getOrders(){
setTimeout(()=>{
let data = '订单数据'
iterator.next(data)
},1000)
}
function getGoods(){
setTimeout(()=>{
let data = '商品数据'
iterator.next(data)
},1000)
}
function * gen(){
let users = yield getUsers();
console.log(users)
let orders = yield getOrders()
console.log(orders)
let goods = yield getGoods()
console.log(goods)
}
let iterator=gen()
iterator.next()
</script>
</body>
</html>
输出;
|