Es6(迭代器、set、map、async、Generator、promise)

迭代器

迭代器(Iterator)就是这样一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署Iterator接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)

迭代器的作用:

1、为各种数据结构,提供一个统一的、简便的访问接口。
2、 使得数据结构的成员能够按某种次序排列
3、es6创造了一种新的遍历命令for…of循环,iterator接口主要供for…of消费。

迭代器的遍历过程

  1. 创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
  2. 第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。
  3. 第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。
  4. 不断调用指针对象的next方法,直到它指向数据结构的结束位置。
//迭代器实现了Iterator接口,只要有实现了Iterator就可以使用for-of遍历
let arr=[1,2,3,4,5];
console.log(arr.keys());
console.log(arr.values());
console.log(arr.entries());
// keys values entries 当前变量是迭代器对象
// 迭代器对象实现了Iterator接口,只要实现了迭代接口就可以使用for-of 遍历
// let [a,b]=10; 报错10 is not iterable
let str='hello'; //实现了迭代器接口,可以遍历
// console.log(a,b);
for(let key of str){
    console.log(key)
}
// 以前遍历字符串
let [...a]=str;
console.log(a)
let result=str.split("")
console.log(result);
for(i=0;i<str.length;i++){
    console.log(str.charAt(i))
}

//遍历迭代器对象
let keys=arr.keys()
for(let key of keys){
    console.log(key)
}
let values=arr.values();
for(let value of values){
    console.log(value,'--------')
}
let entries=arr.entries();
for(let entry of entries){
    console.log(entry)
}
while(!(result=keys.next()).done){
    console.log(result)
}
/* for-of实现原理就是调用迭代器的next()方法,第一次调用将指针指向数据结构的第一个成员,依次调用依次指向,直到没有成员可以指向,done为true
	迭代过程:创建一个指针对象,指向当前的数据结构起始位置;
			第一次调用指针对象的next方法,指向数据结构的第一个成员;
            第二次调用指针对象的next方法,指向数据结构的第二个成员;
			直到done为true,指向数据结构的结束位置;*/
let keys=arr.keys();
let values=arr.values();
let entries=arr.entries()
console.log(keys.next())
console.log(keys.next())
console.log(keys.next())
console.log(keys.next())
console.log(keys.next())
console.log(keys.next())
console.log(entries.next())

具备tterator接口的数据结构:

array、map、set、string、typedArray、arguments、NodeList

forEach、for in、for of 三者的区别:

1、foreach更多的是用来遍历数组
2、for in 一般常用来遍历对象或json
3、for of 数组对象都可以遍历,遍历对象需要通过object.keys()

Set

Set类似于数组,但是成员的值都是唯一的,没有重复的值。Set 本身是一个构造函数,用来生成 Set 数据结构。Set 构造函数可以接受一个数组(或者具有 iterable 接口的其他数据结构)作为参数,用来初始化。

var set = new Set()
// 添加元素
set.add('hello')
set.add('world')
set.add('world')
console.log(set);//Set(2) { 'hello', 'world' }
// 删除元素
set.delete('hello')
console.log(set);//Set(1) { 'world' }
// 遍历
let keys = set.keys()
let values = set.values()
let entries = set.entries()
console.log(keys,values,entries);//[Set Iterator] { 'world' } [Set Iterator] { 'world' } [Set Entries] { [ 'world', 'world' ] }
set.forEach((value)=>{
    console.log(value);//world
})
// 判断有没有某个成员
set.has('hello');//返回布尔值true或者false
// 清空set
set.clear()
// 返回set成员个数
set.size()

set的应用

let set = new Set([1,2,3,4,5,2,3])
console.log(set);//Set(5) { 1, 2, 3, 4, 5 }
// 数组去重
let arr = [1,2,3,4,2,3,5]
let result = new Set(arr)//Set(5) { 1, 2, 3, 4, 5 }
console.log(result);
// 将字符串转换为数组
let [...arr1] = 'hello'
// 将set集合转换为数组
let [...arr2] = result
console.log(arr2);//[ 1, 2, 3, 4, 5 ]
console.log([...new Set(arr)]);//[ 1, 2, 3, 4, 5 ]

let s = new Set()
s.add([1])
s.add([1])
console.log(s);//Set(2) { [ 1 ], [ 1 ] }
console.log(s.size);//2

Map集合

Map类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。Map 可以接受一个数组作为参数。该数组的成员是一个个表示键值对的数组。


let obj = {
    name:'zhangsan',
    age:13,
}
// 遍历键值对组成的数组
let arr = Object.entries(obj)
console.log(arr);//[ [ 'name', 'zhangsan' ], [ 'age', 13 ] ]'
// 将数组作为参数放到map中
let map = new Map(arr)
console.log(map);//Map(2) { 'name' => 'zhangsan', 'age' => 13 }
// 添加元素
map.set('1','1')
console.log(map);//Map(3) { 'name' => 'zhangsan', 'age' => 13, '1' => '1' }
// 删除元素
map.delete('name')
console.log(map);//Map(2) { 'age' => 13, '1' => '1' }
// 获取元素
console.log(map.get('age'));//13
// 遍历
let keys = map.keys()
let values = map.values()
let entries = map.entries()
console.log(keys,values,entries);//[Map Iterator] { 'age', '1' } [Map Iterator] { 13, '1' } [Map Entries] { [ 'age', 13 ], [ '1', '1' ] } 
map.forEach((value,key)=>{
    console.log(value,key);//13 age   1 1
    
})

map 和object的区别

  • 意外的键:
    Map 默认情况不包含任何键。只包含显式插入的键
    一个 Object 有一个原型, 原型链上的键名有可能和你自己在对象上的设置的键名产生冲突。

  • 键的类型:
    一个 Map的键可以是任意值,包括函数、对象或任意基本类型。
    一个Object 的键必须是一个 String 或是Symbol。

  • 键的顺序:
    Map 中的 key 是有序的。因此,当迭代的时候,一个 Map 对象以插入的顺序返回键值。
    一个 Object 的键是无序的。注意:自ECMAScript 2015规范以来,对象确实保留了字符串和Symbol键的创建顺序; 因此,在只有字符串键的对象上进行迭代将按插入顺序产生键。

  • Size
    Map 的键值对个数可以轻易地通过size 属性获取
    Object 的键值对个数只能手动计算

  • 迭代
    Map 是 iterable 的,所以可以直接被迭代。
    迭代一个Object需要以某种方式获取它的键然后才能迭代。

  • 性能
    map在频繁增删键值对的场景下表现更好。
    object在频繁添加和删除键值对的场景下未作出优化。

async异步函数

async函数是使用async关键字声明的函数。async函数是AsyncFunction构造函数的实例,并且其中允许使用await关键字。
async和await关键字让我们可以利用一种更加简洁的方式写出基于promise的异步行为就好像搭配使用了生成器和promise,而无需可以地链式调用promise。
await关键字只在async函数内有效。如果你在async函数体之外使用它,就会抛出语法错误 SyntaxError 。async/await的目的为了简化使用基于promise的API时所需的语法。
async/await的行为就好像搭配使用了生成器和promise。async函数一定会返回一个promise对象。如果一个async函数的返回值看起来不是promise,那么它将会被隐式地包装在一个promise中。

简单来说,是一个函数,是一个异步编程的解决方案,内部封装了generator函数,是一个语法糖,内部自带执行器,与await配合使用,异步编程,同步处理。

async function loadArticle() {
			try {
				let res = await axios.get('url')
				console.log(res.data.data);
			} catch(error) {
				throw new Error('请求失败');
			} finally {
				console.log('最终执行');
			}
		}
loadArticle()

Generator

是ES6提供的一种异步编程解决方案,语法不同于普通函数;简单的把Generator 理解为一个状态机,封装了多个内部状态。执行Generator 函数会返回一个迭代器对象,可以通过调用迭代器next依次遍历Generator函数内部的每一个状态。

			//总结Generator函数
        // 异步编程解决方案  异步代码 同步编写
        function* test(){
            let res=yield 1;
            console.log(res);//100 是下方next的参数 
            yield 2;
        }
        let result=test();//拿到的是迭代器对象 
        result.next();
        result.next(100);//拿到的不是yield后面的状态描述
        //Async 
        //异步函数同步编程
        async function test(){
            let res=await $.get();
            console.log(res)
        }

Promise

传统的异步编程的解决方案是使用回调函数,但是这样就会导致嵌套过深,产生回调地狱,而promois是一种异步编程解决方案,因为调用返回的是一个promise对象,避免了层层嵌套的回调函数,可以链式调用降低了操作难度

在异步编程中,许多操作都会放在回调函数(callback)中,有时候需要拿到上一个异步操作的返回值再做第二次请求。

asyncOperation(data => {
  // 处理 `data`
  anotherAsync(data2 => {
      // 处理 `data2`
      yetAnotherAsync(() => {
          // 完成
      })
  })
})

上面代码中,每增加一个异步请求,就会多添加一层回调函数的嵌套,过多的回调也就让我们陷入“回调地狱”,让代码变得不易阅读与维护。

引入promises之后的代码

promiseSomething()
  .then(data => {
    // 处理 `data`
    return anotherAsync()
  })
  .then(data2 =>{
    // 处理 `data2`
    return yetAnotherAsync()
  })
  .then(() => {
    // 完成
  })

Promises 将嵌套的 callback,改造成一系列的.then的连缀调用,去除了层层缩进的糟糕代码风格

注意:promise本身不是异步,往往内部都是封装一个异步任务。

promise状态

1、pending(进行中):等待状态,比如正在进行网络请求或者定时器没有到时间
2、fulfilled(已成功):满足状态,当主动回调了resolve时,就该处于该状态,并且回调.then()
3、rejected(已失败):拒接状态,当主动回调了reject时,就处于该状态,并且回调。catch()

特点

  • 待定状态的promise对象要么会通过一个值被兑现(fullfilled),要么通过一个原因(错误)被拒绝(rejected)
  • 当这些情况发生之一发生时,我们用promise的ten方法排列起来的相关处理程序就会被调用。
  • promise.prototype.thenpromise.prototype.catch方法返回的是promise,所以它们可以被链式调用

promise的三个实例方法

  • then() 方法

    then是实例状态发生改变时的回调函数,第一个参数是resolved状态的回调函数,第二个参数是rejected状态的回调函数
    then方法返回的是一个新的Promise实例,也就是promise能链式书写的原因

  • catch 方法
    当出现异常 则需要catch方法进行捕获

-finally()方法
方法用于指定不管 Promise 对象最后状态如何,都会执行的操作

创建promise

Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。

promise
	.then(value=>{
		//成功回调,接收的就是容器中的resolve函数
		//容器中resolve函数传的是什么,这里接收就是什么
		console.log(value)
	})
	.catch(error=>{
		//失败的回调,接收的就是容器中的reject函数
		console.log(error)
	})

链式写法

// 封装promise api
function fzPromise(isFlag,data,err){
    return new Promise((resolve,rejecte)=>{
        if(isFlag){
            resolve(data)
        } else {
            rejecte(err)
        }
    })
}
const promiseOne = new fzPromise(true,1,'操作失败')
const promiseTwo = new fzPromise(true,2,'操作失败')
const promiseThree = new fzPromise(flase,3,'操作失败')

// promiseOne 的resolve
.then((data)=>{
    console.log(data);
    // 当promiseOne读取成功 的那概念函数return的结果就能在后面的then中的回调函数接收到
    return promiseTwo
},(err)=>{
    console.log(err);
})
// 这里是promiseTwo的resolve
.then((data)=>{
    console.log(data);
    return promiseThree
},(err)=>{
    // 因为promiseThree是flase,所以结果是reject传的'操作失败'
    console.log(err);
})

//1
//2
//操作失败

promise 封装ajax

let ajax = function(url,params,type='post'){
    return new Promise((resolve,reject)=>{
        $.ajax({
            type,
            url,
            data:params,
            dataType:'json',
            success(res){
                resolve(res)
            },
            error(res){
                reject('相应错误')
            }
        })
    })
}
// 使用示例
ajax('url',{id:1}).then(res=>{
    console.log(res);
})

promise其他静态方法

  • Promise.resolve()
    方法返回一个以给定值解析后的Promise对象
    定值会有以下的几种情况

1、如果这个值是一个promise,那么将返回这个promise
2、如果不是具有then()方法的对象,或者根本就不是对象,Promise.resolve()会返回一个新的Promise对象,状态为resolved
3、没有参数时,直接返回一个resolve状态的Promise对象

  • Promise.reject()
    Promise.reject(reason)方法也会返回一个新的Promise实例,该实例的状态为rejected
const p = Promise.reject('出错了')
// 等同于
const p = new Promise((resolve,reject)=> reject('出错了'))
p.then(null,function(s){console.log(s);})
  • any()方法
    接收一个Promise可迭代对象,只要其中的一个 promise 成功,就返回那个已经成功的 promise 。如果可迭代对象中没有一个 promise 成功(即所有的 promises 都失败/拒绝),就返回一个失败的 promise 和AggregateError类型的实例,它是 Error 的一个子类,用于把单一的错误集合在一起。本质上,这个方法和Promise.all()是相反的。
const pErr = new Promise((resolve, reject) => {
  reject("总是失败");
});

const pSlow = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, "最终完成");
});

const pFast = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, "很快完成");
});

Promise.any([pErr, pSlow, pFast]).then((value) => {
  console.log(value);
  // pFast fulfils first
})

  • all()方法
    方法接收一个promise的iterable类型(注:Array,Map,Set都属于ES6的iterable类型)的输入,并且只返回一个Promise实例
const p = Promise.all([p1, p2, p3]);

实例p的状态由p1,p2,p3决定,分两种情况:
只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数
只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数

  • race() 方法
    该方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例
const p = Promise.race([p1, p2, p3]);

1、只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变
2、率先改变的 Promise 实例的返回值则传递给p的回调函数

Promise和async-await的区别

promise

promise是异步编程的一种解决方案,比起传统的解决方案-----回调函数和事件更加强大;promise相当于一个容器,里面存放着成功和失败的结果,这些解决方案一旦生成时无法改变的

async-await

async-await 也是一种异步解决方案,它遵循的时Generator函数的与反唐,拥有内置的执行器,不需要额外调用函数,返回一个promise对象。

区别

1、Promise的出现解决了传统的callback函数导致的“回调地狱”问题,但它的语法导致了它向纵向发展形成了一个回调链,遇到复杂的业务场景,这样的语法也是不美观的。而async-await代码看起来会简洁些,使得异步代码看起来像同步代码,await的本质是可以提供等同于“同步效果”的等待异步返回能力的语法糖,只有这一句代码执行完,才会执行下一句。
2、async-await与Promise一样,是非阻塞的。
3、async-await是基于Promise实现的,可以说是改良版的promise,它不能用于普通的回调函数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值