实例分析Array.from(arr)与[...arr]到底有何不同


Posted in Javascript onApril 09, 2019

写在开头:

在正文开始之前我们先说明一下类数组(估计大家一定不会陌生)

类数组的特点

1.有索引

2.有长度

3.是个对象

4.能被迭代

实例分析Array.from(arr)与[...arr]到底有何不同

特点说明:对于类数组的特点前三个我就不做说明了哈,主要就是最后一个,能被迭代需要具备什么呢?由图我们可以看出有一个[Symbol.iterator]属性指向该对象的默认迭代器方法。那么它又是如何实现的呢?

迭代器(iterator)

作用(参考阮一峰老师的ES6)

1.为各种数据结构提供一个统一的,简单的访问接口

2.使数据结构的成员能按照某种次序排序

3.供for...of循环消费

工作原理

1.创建一个指针对象,指向当前数据结构的起始位置(并且有一个next方法)

2.第一次调用对象的next方法,可以将指针指向数据结构的第一个成员

3.第二次调用对象的next方法,可以将指针指向数据结构的第二个成员

4.不断调用对象的next方法直到他指向数据结构的结束为止

注:每一次调用next方法都会返回一个包含value和done两个属性的对象,前者代表当前指针指向的数据结构成员的值,后者代表迭代是否结束

举例说明

// 首先我们先创建一个待迭代的对象
let obj = {0:'Gu',1:'Yan',2:'No.1',length:3};
console.log([...obj]);// 报错 Uncaught TypeError: obj is not iterable
console.log(Array.from(obj));// ["Gu", "Yan", "No.1"]
// 接下来我们给待迭代对象添加一个迭代器
obj[Symbol.iterator] = function(){
 let index = 0;
 let self = 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 }

实例分析Array.from(arr)与[...arr]到底有何不同

生成器配合yield来使用如果碰到yield会暂停执行

function* guYan(){
 yield 1,
 yield 2,
 yield 3
}
let it = 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的结果作为值
 let index = 0;
 while(index !== this.length){
 yield this[index++]
 }
}
console.log([...obj]) // ["Gu", "Yan", "No.1"]
console.log(Array.from(obj));// ["Gu", "Yan", "No.1"]

generatour 函数的执行顺序分析(配合图片)

function* guYan(){
 let a = yield 1;
 console.log('a',a);
 let b = yield 2;
 console.log('b',b);
 let c = yield 3;
 console.log('c',c);
}
let it = guYan();
//第一次调用it.next()
it.next() // 什么都没有输出
// 第二次调用
it.next() // a undefined 
/*如果我们第二次是传入参数调用*/
it.next(100) // a 100
// 第三次调用
it.next(200) // b 200
// 第四次调用 
it.next(300) // c 300

实例分析Array.from(arr)与[...arr]到底有何不同

当generator函数遇到Promise来处理异步串行

代码示例采用node的fs模块来模拟异步

// 实现前提 同级目录下创建name.txt age.txt 文件;name.txt中存储age.txt,age.txt中存储20
let fs = require('mz/fs');//我们直接使用mz包来实现fs的promise化
let path = require('path');
function* guYan() {
 let name = yield fs.readFile(path.resolve(__dirname, './name.txt'), 'utf-8');
 name = yield './' + name;
 let age = yield fs.readFile(path.resolve(__dirname, name), 'utf-8');
 return age;
}
let it = 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库)

let fs = require('mz/fs');
let path = require('path');
function* guYan() {
 let name = yield fs.readFile(path.resolve(__dirname, './name.txt'), 'utf-8');
 name = yield './' + name;
 let age = yield fs.readFile(path.resolve(__dirname, name), 'utf-8');
 return age;
}
function co(it){
 return new Promise((resolve,reject)=>{
  function next(val){
   let {value , done} = it.next(val);
   if(done){
    return resolve(value);
   }
   Promise.resolve(value).then(data=>{
    next(data)
   })
  }
  next();
 })
}
co(guYan()).then(data=>{
 console.log(data); // 20
})

通过async+await 来简化

// 上述代码可以简化为
let fs = require('mz/fs');
let path = require('path');
async function guYan() {
 let name = await fs.readFile(path.resolve(__dirname, './name.txt'), 'utf-8');
 name = './' + name;
 let age = await fs.readFile(path.resolve(__dirname, name), 'utf-8');
 return age;
}
// 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

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
说说JSON和JSONP 也许你会豁然开朗
Sep 02 Javascript
jquery如何通过name名称获取当前name的value值
Dec 20 Javascript
用javascript替换URL中的参数值示例代码
Jan 27 Javascript
使用javascript获取页面名称
Dec 23 Javascript
JavaScript实现的encode64加密算法实例分析
Apr 15 Javascript
使用 JavaScript 进行函数式编程 (一) 翻译
Oct 02 Javascript
原生js配合cookie制作保存路径的拖拽
Dec 29 Javascript
轻松理解JavaScript闭包
Mar 14 Javascript
详解vue2.0 使用动态组件实现 Tab 标签页切换效果(vue-cli)
Aug 30 Javascript
微信小程序实现点击按钮修改文字大小功能【附demo源码下载】
Dec 06 Javascript
js统计页面上每个标签的数量实例代码
May 29 Javascript
浅析Vue项目中使用keep-Alive步骤
Jul 27 Javascript
浅谈Vue.js组件(二)
Apr 09 #Javascript
4 种滚动吸顶实现方式的比较
Apr 09 #Javascript
vue响应式系统之observe、watcher、dep的源码解析
Apr 09 #Javascript
浅谈发布订阅模式与观察者模式
Apr 09 #Javascript
vue使用keep-alive保持滚动条位置的实现方法
Apr 09 #Javascript
浅谈JavaScript闭包
Apr 09 #Javascript
使用Three.js实现太阳系八大行星的自转公转示例代码
Apr 09 #Javascript
You might like
PHP VS ASP
2006/10/09 PHP
PHP 开源AJAX框架14种
2009/08/24 PHP
PHP常用技巧总结(附函数代码)
2012/02/04 PHP
PHP整数取余返回负数的相关解决方法
2014/05/15 PHP
php字符串替换函数substr_replace()用法实例
2015/03/17 PHP
Yii2框架视图(View)操作及Layout的使用方法分析
2019/05/27 PHP
用js遍历 table的脚本
2008/07/23 Javascript
js removeChild 障眼法 可能出现的错误
2009/10/06 Javascript
javascript中最常用的继承模式 组合继承
2010/08/12 Javascript
将nodejs打包工具整合到鼠标右键的方法
2013/05/11 NodeJs
Jquery Uploadify多文件上传带进度条且传递自己的参数
2013/08/28 Javascript
JS小功能(操作Table--动态添加删除表格及数据)实现代码
2013/11/28 Javascript
获取3个数组不重复的值的具体实现
2013/12/30 Javascript
jquery的ajax简单结构示例代码
2014/02/17 Javascript
jquery取消选择select下拉框示例代码
2014/02/22 Javascript
原生javascript实现拖动元素示例代码
2014/09/01 Javascript
javascript实现了照片拖拽点击置顶的照片墙代码
2015/04/03 Javascript
JavaScript学习笔记之数组求和方法
2016/03/23 Javascript
小程序实现多选框功能
2018/10/30 Javascript
浅谈小程序 setData学问多
2019/02/20 Javascript
微信小程序实现的canvas合成图片功能示例
2019/05/03 Javascript
使用layer弹窗,制作编辑User信息页面的方法
2019/09/27 Javascript
[01:45]2014DOTA2 TI预选赛预选赛 战前探营!
2014/05/21 DOTA
Python常见MongoDB数据库操作实例总结
2018/07/24 Python
对python 中re.sub,replace(),strip()的区别详解
2019/07/22 Python
python多继承(钻石继承)问题和解决方法简单示例
2019/10/21 Python
使用Jupyter notebooks上传文件夹或大量数据到服务器
2020/04/14 Python
Ralph Lauren拉夫·劳伦美国官网:带有浓郁美国气息的高品味时装品牌
2017/11/01 全球购物
局部内部类是否可以访问非final变量?
2013/04/20 面试题
计算机专业自我鉴定
2013/10/15 职场文书
大学生职业生涯规划书范文
2014/01/14 职场文书
小学生节水倡议书
2015/04/29 职场文书
诚信教育主题班会
2015/08/13 职场文书
Centos环境下Postgresql 安装配置及环境变量配置技巧
2021/05/18 PostgreSQL
Python卷积神经网络图片分类框架详解分析
2021/11/07 Python
Vue操作Storage本地化存储
2022/04/29 Vue.js