array.from(arr)与[...arr]的区别是什么-亚博电竞手机版
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]的区别是什么的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注恰卡编程网行业资讯频道,感谢各位的阅读!