ECMAScript
迭代器
迭代器(lterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署iterator接口(对象里面的属性),就可以完成遍历操作
1.ES6创造了一种新的遍历命令for…of遍历,iterator接口主要供for…of消费
2.原生具备iterator接口的数据(可用for of遍历)
2.1 Array
2.2 Arguments
2.3 Set
2.4 Map
2.5 String
2.6 TypedArray
2.7 NodeList
工作原理:
1.创建一个指针对象,指向当前数据结构的起始位置
2.第一次调用对象的next方法,指针自动指向数据结构的第一个成员
3.接下来不断调用next方法,指针一直往后移动,直到指向最后一个成员
4.每调用next方法返回一个包含value和done属性的对象
注意:需要自定义遍历数据的时候,要想到迭代器
<!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>
const person = ['唐三藏', '孙悟空', '猪八戒', '沙悟净'];
//使用for..in遍历数组
// item保存的是键名
/* for (let item in person) {
//输出的是对应的下标
// 0/1/2/3
console.log(item);
}
//使用for..of遍历数组
// item保存的是健值
for (let item of person) {
//输出的是内容
// 唐三藏/孙悟空/猪八戒/沙悟净
console.log(item);
} */
let obj = person[Symbol.iterator]();
console.log(obj.next()); //{value: '唐三藏', done: false}
console.log(obj.next()); //{value: '孙悟空', done: false}
console.log(obj.next()); //{value: '猪八戒', done: false}
console.log(obj.next()); //{value: '沙悟净', done: false}
console.log(obj.next()); //{value: undefined, done: true}
</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>
// 声明一个对象
const obj = {
name: '大学生们',
persons: [
'张三',
'李四',
'王五',
'周六'
],
[Symbol.iterator]() {
// 索引变量
let index = 0;
let _this = this;
// 需要返回一个对象
return {
// 对象里面要有一个next方法
next: function() {
// 在这里使用this,会有问题
if (index < _this.persons.length) {
const res = {
value: _this.persons[index],
done: false
};
// 索引自增
index++;
return res;
} else {
// 内容遍历完毕,返回undefined
return {
value: undefined,
done: true
};
}
}
// 箭头函数没有自己的this,它的this是这个函数创建时所在的所用域的this,
/* next: () => {
if (index < this.persons.length) {
const res = {
value: this.persons[index],
done: false
};
index++;
return res;
} else {
return {
value: undefined,
done: true
};
}
} */
}
}
};
// 遍历对象
for (let item of obj) {
console.log(item); //Uncaught TypeError: obj is not iterable
}
</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* func() {
// console.log('hello,111');
// yield后面跟一个表达式或者字面量
// yield函数代码的分割符
// 函数开始到第一个yield是一块,第一个yield到第二个yield是一块,
// 第二个yield到第三个yield是一块,第三个yield到函数结束是一块
yield '111';
// console.log('hello,222');
yield '222';
// console.log('hello,333');
yield '333'
// console.log('hello,444');
};
// obj是一个生成器对象(可迭代)
let obj = func();
// console.log(obj);
// 必须要调用next函数才能运行
// 用next()来控制代码的向下执行
// 调用一次next(),就会执行一段
/* obj.next(); //hello,111
obj.next(); //hello,222
obj.next(); //hello,333
obj.next(); //hello,444 */
// 遍历
for (const item of func()) {
// 遍历结果是yield后面的表达式
console.log(item);
}
</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* gen(arg) {
// console.log('hello,1111');
console.log(arg);
yield 111;
yield 222;
yield 333;
};
// 生成器对象(可迭代)
// 传入实参
let obj = gen('AAA');
/* console.log(obj);
// obj.next() //hello,1111
// value是yield后面的表达式或者字面量;done为false,说明遍历还未结束
console.log(obj.next()); //{value: 111, done: false}
console.log(obj.next()); //{value: 222, done: false}
console.log(obj.next()); //{value: 333, done: false}
// done: true:表明遍历结束
console.log(obj.next()); //{value: undefined, done: true} */
// 第一次调用next方法,是执行gen函数的第一段代码(函数的开始到第一个yield)
console.log(obj.next()); //AAA/{value: 111, done: false}
// next方法可以传入实参,这个参数作为上一个yield语句的返回结果
console.log(obj.next('BBB')); //{value: 222, done: false}
</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>
// 异步编程、文件操作、网络操作(ajax,request),数据操作
// 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);
timer.next();
}, 1000)
};
function two() {
setTimeout(() => {
console.log(222);
timer.next();
}, 2000)
};
function three() {
setTimeout(() => {
console.log(333);
timer.next();
}, 3000)
};
// 创建生成器函数
function* gen() {
// 先执行这个
yield one();
// 再执行这个
yield two();
// 最后执行这个
yield three();
};
// 创建生成器对象
const timer = gen();
// 调用next()
timer.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 getUser() {
setTimeout(() => {
let data = '用户数据';
// 调用next方法,并且将数据传入,这里运行第二段函数,参数作为上一次调用next方法的返回值
obj.next(data)
}, 1000)
};
function getOrders() {
setTimeout(() => {
let data = '订单数据';
// 调用next函数,传入参数,作为上一次调用的返回值
obj.next(data)
}, 1000)
};
function getGoods() {
setTimeout(() => {
let data = '商品数据';
// 调用next函数,传入参数,作为上一次调用的返回值
obj.next(data)
}, 1000)
};
// 创建生成器
function* gen() {
let user = yield getUser();
// console.log(user); //用户数据
let order = yield getOrders();
// console.log(order);
let goods = yield getGoods();
// console.log(goods);
};
// 创建生成器对象
const obj = gen();
// 调用生成器函数,这里运行第一段函数
obj.next(); //getUser()
</script>
</body>
</html>