Array.from(arr)与[...arr]的区别是什么?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。
类数组的特点
1.有索引
2.有长度
3.是个对象
4.能被迭代
特点说明:对于类数组的特点前三个我就不做说明了哈,主要就是最后一个,能被迭代需要具备什么呢?由图我们可以看出有一个[Symbol.iterator]属性指向该对象的默认迭代器方法。那么它又是如何实现的呢?
迭代器(iterator)
作用(参考阮一峰老师的ES6)
1.为各种数据结构提供一个统一的,简单的访问接口
2.使数据结构的成员能按照某种次序排序
3.供for...of循环消费
工作原理
1.创建一个指针对象,指向当前数据结构的起始位置(并且有一个next方法)
2.第一次调用对象的next方法,可以将指针指向数据结构的第一个成员
3.第二次调用对象的next方法,可以将指针指向数据结构的第二个成员
4.不断调用对象的next方法直到他指向数据结构的结束为止
注:每一次调用next方法都会返回一个包含value和done两个属性的对象,前者代表当前指针指向的数据结构成员的值,后者代表迭代是否结束
举例说明
//首先我们先创建一个待迭代的对象 letobj={0:'Gu',1:'Yan',2:'No.1',length:3}; console.log([...obj]);//报错UncaughtTypeError:objisnotiterable console.log(Array.from(obj));//["Gu","Yan","No.1"] //接下来我们给待迭代对象添加一个迭代器 obj[Symbol.iterator]=function(){ letindex=0; letself=this; return{ next(){ return{value:self[index],done:index++===self.length} } } } console.log([...obj])//["Gu","Yan","No.1"] console.log(Array.from(obj));//["Gu","Yan","No.1"]
通过上面的例子我相信文章前的你肯定可以懂得标题的答案了吧
虽然我们可以手动写出迭代器函数但是你不觉得很麻烦吗,所以又到了我们的另外一个知识点那就是generator生成器
generator 生成器
生成器返回的是迭代器,迭代器有next方法,调用next返回value和done
function*guYan(){ } console.log(guYan())//Object[Generator]{} console.log(guYan().next)//[Function:next] console.loh(guYan().next())//{value:undefined,done:true}
生成器配合yield来使用如果碰到yield会暂停执行
function*guYan(){ yield1, yield2, yield3 } letit=guYan(); console.log(it.next())//{value:1,done:false} console.log(it.next())//{value:2,done:false} console.log(it.next())//{value:3,done:false} console.log(it.next())//{value:undefined,done:true}
通过生成器给obj增加迭代器
obj[Symbol.iterator]=function*(){ //每次浏览器都会不停的调用next方法把yield的结果作为值 letindex=0; while(index!==this.length){ yieldthis[index++] } } console.log([...obj])//["Gu","Yan","No.1"] console.log(Array.from(obj));//["Gu","Yan","No.1"]
generatour 函数的执行顺序分析(配合图片)
function*guYan(){ leta=yield1; console.log('a',a); letb=yield2; console.log('b',b); letc=yield3; console.log('c',c); } letit=guYan(); //第一次调用it.next() it.next()//什么都没有输出 //第二次调用 it.next()//aundefined /*如果我们第二次是传入参数调用*/ it.next(100)//a100 //第三次调用 it.next(200)//b200 //第四次调用 it.next(300)//c300
当generator函数遇到Promise来处理异步串行
代码示例采用node的fs模块来模拟异步
//实现前提同级目录下创建name.txtage.txt文件;name.txt中存储age.txt,age.txt中存储20 letfs=require('mz/fs');//我们直接使用mz包来实现fs的promise化 letpath=require('path'); function*guYan(){ letname=yieldfs.readFile(path.resolve(__dirname,'./name.txt'),'utf-8'); name=yield'./'+name; letage=yieldfs.readFile(path.resolve(__dirname,name),'utf-8'); returnage; } letit=guYan(); let{value}=it.next(); value.then(data=>{ let{value}=it.next(data); Promise.resolve(value).then(data=>{ let{value}=it.next(data) value.then(data=>{ let{value}=it.next(data); console.log(value)//20 }) }) })
对上述代码调用进行封装(实现co库)
letfs=require('mz/fs'); letpath=require('path'); function*guYan(){ letname=yieldfs.readFile(path.resolve(__dirname,'./name.txt'),'utf-8'); name=yield'./'+name; letage=yieldfs.readFile(path.resolve(__dirname,name),'utf-8'); returnage; } functionco(it){ returnnewPromise((resolve,reject)=>{ functionnext(val){ let{value,done}=it.next(val); if(done){ returnresolve(value); } Promise.resolve(value).then(data=>{ next(data) }) } next(); }) } co(guYan()).then(data=>{ console.log(data);//20 })
通过async+await 来简化
//上述代码可以简化为 letfs=require('mz/fs'); letpath=require('path'); asyncfunctionguYan(){ letname=awaitfs.readFile(path.resolve(__dirname,'./name.txt'),'utf-8'); name='./'+name; letage=awaitfs.readFile(path.resolve(__dirname,name),'utf-8'); returnage; } //async函数执行后返回一个promise //可以使用try+catch,但如果使用try+catch返回的就是真 guYan().then(data=>{ console.log(data); })
处理方案比较
1.callback 多个请求并发 不好管理 链式调用 导致回调嵌套过多
2.promise优点 可以优雅的处理异步 处理错误,基于回调的,还是会有嵌套问题
3.generator + co 让代码像同步(比如dva)不能支持try catch
4.async + await 可以是异步像同步一样处理,返回一个promise 支持try catch
看完上述内容,你们掌握Array.from(arr)与[...arr]的区别是什么的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注恰卡编程网行业资讯频道,感谢各位的阅读!
相关文章
本站已关闭游客评论,请登录或者注册后再评论吧~