◼ 但是上面的代码整体来说看起来是有点奇怪的:
我们获取一个数组的时候,需要自己创建一个index变量,再创建一个所谓的迭代器对象;
事实上我们可以对上面的代码进行进一步的封装,让其变成一个可迭代对象;
◼ 什么又是可迭代对象呢?
它和迭代器是不同的概念;
当一个对象实现了iterable protocol协议时,它就是一个可迭代对象;
这个对象的要求是必须实现@@iterator 方法,在代码中我们使用Symbol.iterator 访问该属性;
◼ 当然我们要问一个问题,我们转成这样的一个东西有什么好处呢?
当一个对象变成一个可迭代对象的时候,就可以进行某些迭代操作;
比如for...of 操作时,其实就会调用它的@@iterator 方法;
手写一个可迭代对象
// 将infos变成可迭代对象
//1.必须有一个函数叫:[Symbol.iterator]
//2.这个函数需要返回一个迭代器(这个迭代器用于返回当前这个对象)
//3.
const infos = {
friends:["kebo","james","curry"],
[Symbol.iterator](){
let index = 0
const infosIterator = {
next(){
if(index < infos.friends.length){
return {done:false,value:infos.friends[index++]}
}
else{
return{done:true,value:undefined}
}
}
}
return infosIterator
}
}
// 可迭代对象必然具备下面的特点
// 一定可以这样拿到一个函数执行后一定拿到一个迭代器
const iterator = infos[Symbol.iterator]()
// 一定可以通过迭代器.next()
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
// 可迭代对象可以进行for..of
for(const item of infos){
console.log(item)
}
可迭代对象迭代出来的值为key:value
// 将infos变成可迭代对象
//1.必须有一个函数叫:[Symbol.iterator]
//2.这个函数需要返回一个迭代器(这个迭代器用于返回当前这个对象)
//3.
const infos = {
friends:["kebo","james","curry"],
// 迭代infos中的friends数组
// [Symbol.iterator](){
// let index = 0
// const infosIterator = {
// next: () => {
// if(index < this.friends.length){
// // next()为普通函数时this指向的是iterator并不是infos 所有next函数要用箭头函数this为上层作用域的this
// return {done:false,value:this.friends[index++]}
// }
// else{
// return{done:true,value:undefined}
// }
// }
// }
// return infosIterator
// }
// }
// 迭代infos中的key和value
name:"hdc",
age:21,
height:1.88,
[Symbol.iterator](){
const keys = Object.keys(this)//key的值
const values = Object.values(this)//value值
const entries = Object.entries(this)//key:value值
let index = 0
const iterator = {
next:()=>{
if (index < entries.length){
return {done:false , value:entries[index++],}
}
else{
return{done:true,value:undefined}
}
}
}
return iterator
}
}
// 可迭代对象必然具备下面的特点
// 一定可以这样拿到一个函数执行后一定拿到一个迭代器
// const iterator = infos[Symbol.iterator]()
// // 一定可以通过迭代器.next()
// console.log(iterator.next())
// console.log(iterator.next())
// console.log(iterator.next())
// console.log(iterator.next())
// 可迭代对象可以进行for..of
for(const item of infos){
const [key,value] = item
console.log(`key值为:${key},value值为:${value}`)
}
原生迭代器对象
◼ 事实上我们平时创建的很多原生对象已经实现了可迭代协议,会生成一个可迭代对象的:
String、Array、Map、Set、arguments对象、NodeList集合;
// 1.Array
const names = ["aaa","bbb","ccc"]
for(const name of names){
console.log(name)
}
console.log(names[Symbol.iterator]())
//2.Set
const set = new Set(["aaa","bbb","ccc"])
for (const item of set) {
console.log(item)
}
console.log(set[Symbol.iterator]())
//3.arguments
function foo(){
for (const arg of arguments) {
console.log(arg)
}
console.log(arguments[Symbol.iterator]())
}
foo(111,222,33,44,112,55)
可迭代对象的应用
◼ 那么这些东西可以被用在哪里呢?
JavaScript中语法:for ...of、展开语法(spread syntax)、yield*(后面讲)、解构赋值(Destructuring_assignment);
创建一些对象时:new Map([Iterable])、new WeakMap([iterable])、new Set([iterable])、new WeakSet([iterable]);
一些方法的调用:Promise.all(iterable)、Promise.race(iterable)、Array.from(iterable);
const arrs = ["aaa","bbb","ccc","ddd"]
//JavaScript中语法
//for of 语法
for (const arr of arrs) {
console.log(arr)
}
// 展开运算符
const newArr = [...arrs]
console.log(newArr)
// 结构
const[arr1,arr2,arr3,arr4]=arrs
console.log(arr1,arr2,arr3,arr4)
// 一些类的构造方法中,也是传入一些可迭代对象
const set = new Set(["aaaa","bbbb","cccc"])
自定义类的迭代
◼ 在前面我们看到Array、Set、String、Map等类创建出来的对象都是可迭代对象:
在面向对象开发中,我们可以通过class定义一个自己的类,这个类可以创建很多的对象:
如果我们也希望自己的类创建出来的对象默认是可迭代的,那么在设计类的时候我们就可以添加上@@iterator 方法;
◼ 案例:创建一个classroom的类
教室中有自己的位置、名称、当前教室的学生;
这个教室可以进来新学生(push);
创建的教室对象是可迭代对象;
class classRoom {
constructor(postion,name,students){
this.postion = postion
this.name = name
this.students = students
}
pushStudent(student){
this.students.push(student)
}
[Symbol.iterator](){
let index = 0
const iterator = {
next:()=>{
if(index < this.students.length){
return {done:false,value:this.students[index++]}
}
else{
return {done:true,value:undefined}
}
}
}
return iterator
}
}
const classRoom1 = new classRoom("xxx楼101","WEB教室",["aaa","bbb","ccc"])
classRoom1.pushStudent("ddd")
console.log(classRoom1)
let index = 1
for (const student of classRoom1) {
console.log(`教室的学生${index++}:${student}`)
}
迭代器的中断
◼ 迭代器在某些情况下会在没有完全迭代的情况下中断:
比如遍历的过程中通过break、return、throw中断了循环操作;
比如在解构的时候,没有解构所有的值;
◼ 那么这个时候我们想要监听中断的话,可以添加return方法:
class classRoom {
constructor(postion,name,students){
this.postion = postion
this.name = name
this.students = students
}
pushStudent(student){
this.students.push(student)
}
[Symbol.iterator](){
let index = 0
const iterator = {
next:()=>{
if(index < this.students.length){
return {done:false,value:this.students[index++]}
}
else{
return {done:true,value:undefined}
}
},
// 迭代器中断函数
return:function(){
console.log("箭头到迭代器中断")
return {done:true}
}
}
return iterator
}
}
const classRoom1 = new classRoom("xxx楼101","WEB教室",["aaa","bbb","ccc"])
classRoom1.pushStudent("ddd")
console.log(classRoom1)
let index = 1
for (const student of classRoom1) {
console.log(student)
if (student === "ccc"){
break
}
}