实例分析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 相关文章推荐
jquery 表格的增行删行实现思路
Mar 21 Javascript
js实现回放拖拽轨迹从过程上进行分析
Jun 26 Javascript
javascript中caller和callee详解
Aug 10 Javascript
jQuery mobile转换url地址及获取url中目录部分的方法
Dec 04 Javascript
JavaScript获取图片像素颜色并转换为box-shadow显示
Mar 11 Javascript
JQuery在循环中绑定事件的问题详解
Jun 02 Javascript
JS实现全屏的四种写法
Dec 30 Javascript
jQuery使用siblings获取某元素所有同辈(兄弟姐妹)元素用法示例
Jan 30 Javascript
利用Chrome DevTools直接调试Node.js和JavaScript的方法详解(并行)
Feb 16 Javascript
React中使用collections时key的重要性详解
Aug 07 Javascript
node.js通过axios实现网络请求的方法
Mar 05 Javascript
JavaScript实现数组全排列、去重及求最大值算法示例
Jul 30 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
打造计数器DIY三步曲(上)
2006/10/09 PHP
php中unserialize返回false的解决方法
2014/09/22 PHP
Laravel框架控制器的middleware中间件用法分析
2019/09/30 PHP
laravel 如何实现引入自己的函数或类库
2019/10/15 PHP
JavaScript 组件之旅(三):用 Ant 构建组件
2009/10/28 Javascript
js读取配置文件自写
2014/02/11 Javascript
Jquery仿IGoogle实现可拖动窗口示例代码
2014/08/22 Javascript
JavaScript字符串对象substr方法入门实例(用于截取字符串)
2014/10/16 Javascript
JavaScript 动态加载脚本和样式的方法
2015/04/13 Javascript
node.js插件nodeclipse安装图文教程
2020/10/19 Javascript
JavaScript实现瀑布流以及加载效果
2017/02/11 Javascript
jQuery插件echarts实现的单折线图效果示例【附demo源码下载】
2017/03/04 Javascript
详解Vue中一种简易路由传参办法
2017/09/15 Javascript
JS和JQuery实现雪花飘落效果
2017/11/30 jQuery
js对象数组和对象的使用实例详解
2019/08/27 Javascript
Node 模块原理与用法详解
2020/05/13 Javascript
[49:35]KG vs SECRET 2019国际邀请赛小组赛 BO2 第一场 8.16
2019/08/19 DOTA
[06:48]DOTA2-DPC中国联赛2月26日Recap集锦
2021/03/11 DOTA
开源Web应用框架Django图文教程
2017/03/09 Python
使用11行Python代码盗取了室友的U盘内容
2018/10/23 Python
Python3离线安装Requests模块问题
2019/10/13 Python
Python 日志logging模块用法简单示例
2019/10/18 Python
Python 切分数组实例解析
2019/11/07 Python
jupyter notebook中新建cell的方法与快捷键操作
2020/04/22 Python
python3+openCV 获取图片中文本区域的最小外接矩形实例
2020/06/02 Python
CSS3 制作旋转的大风车(充满童年回忆)
2013/01/30 HTML / CSS
2019史上最全Database工程师题库
2015/12/06 面试题
在职研究生自我鉴定
2013/10/16 职场文书
设计顾问服务计划书
2014/05/04 职场文书
岳麓书院导游词
2015/02/03 职场文书
五一劳动节活动总结
2015/02/09 职场文书
关于感恩的歌曲整理(8首)
2019/08/14 职场文书
开发一个封装iframe的vue组件
2021/03/29 Vue.js
java协程框架quasar和kotlin中的协程对比分析
2022/02/24 Java/Android
python前后端自定义分页器
2022/04/13 Python
python实现简单的三子棋游戏
2022/04/28 Python