41 Symbol、Set和Map、Iterator和Generator、Promise、async函数

 

41 Symbol、Set和Map、Iterator和Generator、Promise、async函数

一、Symbol(了解)

ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。

它是 JavaScript 语言的第七种数据类型。

string,number,undefined,object,null,array,function,boolean

不参加任何运算,经常应用于对象中,当作对象的属性名。

Symbol 值通过Symbol函数生成。

语法:

Symbol()
Symbol(标识符) 标识符没有特殊含义,只是好区分

 

1.基础用法

代码案例:

// let sym1 = Symbol()
// console.log( typeof sym1 );

// let sym2 = Symbol()

// console.log( sym1 == sym2 );//false

 

2.Symbol描述符

代码案例:

let username = Symbol('uname')
let age = Symbol('uage')

 

3.应用场景

一般常用于框架、js内置函数和对象中

 

代码案例:

<script>

function tools (){

   let username = Symbol('uname')
   let age = Symbol('uage')


   let per1 = {
      [username]:'swk',
      [age]:20
  }

   return function(){
       return per1[username]
  }

}

</script>


<script>
   let fn = tools()
   console.log( fn() )
</script>

 

二、Set和Map( 了解 )

1.Set

ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值

1.1基本用法

代码案例:

语法:
let set1 = new Set( arrayLike )
let set1 = new Set(123)  //number 123 is not iterable : 遍历
console.log( set1 );

let set2 = new Set( [11,22,33,11,33,22,44,5] )  
console.log( set2 );
console.log( typeof set2 );//object


 

1.2常见方法

  • size 获取set集合的长度

  • add(值) 给集合添加值,返回新set

  • delete(值) 删除某个值,返回布尔值,表示是否删除成功

  • has(值) 查询这个值是否时集合的成员,返回布尔值

  • clear() 清空集合,没有返回值

代码案例:

    let set1 = new Set( [11,22,33,11,33,22,44,5,100,200,200] )

//   console.log( set1 );
   // set1.add( 300 )
   // set1.add( 300 )
   // set1.delete( 11 )
   // set1.clear( )
   // console.log( set1 );

   console.log( set1.has( 10 ) );//false
   console.log( set1.has( 100 ) );//true

 

1.3 应用

数组去重

代码案例:


let arr1 = [ ...new Set( [11,22,33,11,33,22,44,5] ) ]  
console.log( arr1 );

let arr2 = Array.from( new Set( [11,22,33,11,33,22,44,5]) )
console.log( arr2 );


function spliceRepeatData( array ){

   return Array.from( new Set( array ) )
}


let spliceRepeatData =  array => Array.from( new Set( array ) )

console.log( spliceRepeatData( [11,22,33,11,33,22,44,5,100,200,200] ) )

 

2.Map

ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。

2.1基本用法

代码案例:

语法:
let map1 = new Map( [ [key1,value1],[key2,value2],... ] )

let btn = document.getElementById('btn')

let obj = {
[btn]:'我是标签当作属性名'
}
// alert( btn )
console.log( obj[ btn ] );
console.log( obj['[object HTMLButtonElement]'] )


let map1 = new Map( [ [true,'我是布尔值当作属性'],[ btn,'我是标签对象当作属性名' ] ] )

console.log(map1);
console.log(typeof map1);//object

 

2.2常见方法

  • size 获取Map的长度

  • set(key,val) 添加一条数据

  • get(key) 根据key获取val

  • has(key) 是否存在key

  • delete(key) 删除某条数据

  • clear() 清空所有数据

代码案例:

let map1 = new Map( [ [true,'我是布尔值当作属性'],[ btn,'我是标签对象当作属性名' ] ] )

// console.log(map1);
// console.log(typeof map1);//object

console.log( map1.get( true ) );//我是布尔值当作属性
console.log( map1.get( btn ) );//我是标签对象当作属性名

 

 

三、Iterator和Generator(了解)

1.Iterator

1.1 简介

Iterator是一种循环的新的接口机制,为各种不同的数据结构提供统一的访问或遍历机制, 遍历器, 因为现在有Array / Object / Set / Map / String 5种结构, 所以ES6 加入了Iterator遍历器, 只要拥有这个Iterator遍历器, 就都可以使用for...of进行遍历

for / while / for...in / forEach

1.2 作用

  • 为各种数据结构,提供一个统一的、简便的访问接口

  • 使得数据结构的成员能够按某种次序排列

  • ES6创造了一种新的遍历命令for...of循环,Iterator接口主要供for...of使用

  • Iterator是一个抽象的概念, 具体的实现 for...of / Symbol.iterator

 

1.3 for...of

代码案例:

 let str1 = 'abcd'

for( let val of str1 ){
console.log( val );// a,b,c,d
}

let arr = [11,22,33]
for(let val of arr){
console.log( val );//11,22,33
}

 

注意事项:在使用for...of遍历数据时, 要确保被遍历的数据, 拥有Iterator功能

原生具备iterator接口的结构有:String / Array / Set /Map 唯独没有Object

...

 

1.4 数组和Iterator

代码案例:

let arr = [11,22,33]
for(let val of arr){
console.log( val );//11,22,33
}

 

原理分析:

数据原型上部署了 Symbol.iterator方法 。在我们使用for...of的时候,它自己会调用 这个方法。

 //以数组为例
let arr = [11,22,33]
//console.log( arr );

// console.log( arr[Symbol.iterator] )
let iter = arr[Symbol.iterator]() //返回了一个指针对象
// console.log( iter );
console.log( iter.next() );//11 {value: 11, done: false} 如果为false代表没有遍历完
console.log( iter.next() );//22 {value: 22, done: false}
console.log( iter.next() );//33 {value: 33, done: false}
console.log( iter.next() );//undefined {value: undefined, done: true} 如果为true则遍历完成 。

 

1.5为对象部署iterator接口

代码案例:

let obj = {
username:'swk',
job:'斩妖除魔',
address:'花果山'
}



Object.prototype[Symbol.iterator] = function(){

let values = Object.values( this )
let len = values.length
// console.log( values );
let index = 0 //下标,要依次从values中取值。
return {
next(){
return index >= len ? { value:undefined,done:true } : { value:values[index++],done:false }
}
}
}

 

2.Generator

2.1简介

Generator 函数是 ES6 提供的一种异步编程解决方案

Generator函数是一个状态机, 可控制函数执行过程

可暂停函数(惰性求值), 内部yield可暂停,外部调用next方法可启动。每次返回的是yield后的表达式结果

 

现实开发中,有很多业务是互相依赖的,就产生了回调地狱。而ajax是最容易产生回调地狱的。

但是我们更加习惯使用同步的形式开发业务。

最终:要使用es6的新语法,新特性,把异步变同步。

function fn(){
let result1 = 异步请求1
let result2 = 异步请求2

}

 

2.2特点和用法

普通函数变为generator函数 。只需要在function关键后面加个 *。
function* fn(){
yield 跟代码
}

代码案例:

function* fn(){
console.log('代码开始运行')

yield '请求到了一组商品数据'

yield '根据id获取到了商品详情'

console.log( '代码执行完毕' )
}

let iter = fn() //状态机
// console.log( iter );

console.log( iter.next() )//当碰到yield,停止往下执行 请求到了一组商品数据
console.log( iter.next() )//当碰到yield,停止往下执行 根据id获取到了商品详情
console.log( iter.next() )//当碰到yield,停止往下执行

 

四、Promise(重点)

1.简介

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。

Promise是一个构造函数。它是个容器,Promise里面经常保存了未来才会结束的事件(通常是一个异步操作)

作用:有了Promise对象, 可以将异步操作以同步的流程表达出来, 避免了层层嵌套的回调函数(俗称'回调地狱')

 

回调地狱案例:

/*
es6中的回调地狱参考:
http://api2.xqb.ink/api/courses 获取课程列表,不需要参数
http://api2.xqb.ink/api/course?id=1001 获取单个课程,需要参数id=1001

jquery
https://cdn.bootcdn.net/ajax/libs/jquery/1.9.1/jquery.min.js
*/

// console.log( $ );
$.ajax( {
url:'http://api2.xqb.ink/api/courses',
success(res){
console.log( res,'课程详情数据' );
let id = res.result[1].course_id
// console.log( id );
$.ajax({
url:`http://api2.xqb.ink/api/course?id=${id}`,
success(res){
console.log( res,'单个课程的信息' );
}
})
}
} )

改写成promise并配合async+await案例:

async function fn(){
let result1 = await 异步请求1 是promise对象
let result2 = await 异步请求2 是promise对象
}

 

2.promise的基本用法

语法:


let pro = new Promise( function( resolve,reject ){
//就是未来要做的事情1
....一些业务代码
resolve( 事情1的结果 ) //函数调用
} )

pro.then( function(result){ //then 然后要做的事情2,then函数需要一个回调。then是Promise原型上的方法。
//result 是未来要做的事情1 传递过来的结果
} )

 

代码案例:

   //要求:获取00001号员工的薪金,加20000
//可能会获取0002号员工的薪金。加10000
// console.log( typeof Promise ) //function
let pro = new Promise( function B(resolve1,reject1){ //B 函数是Promise的回调,是在Promise内部执行的。

//做了ajax调用 。
setTimeout( ()=>{
resolve1( 40000) //resolve1是函数。所以才可以调用 。 其实也就是相当于调用的A函数,并且给了A函数的形参res。
} ,1000)
} )


pro.then( function A(res){ //A函数给了resolve1
console.log( res,'我是结果123' );
console.log( res + 20000 );
console.log( res123 );
} )

 

2.1promise状态

完成代表成功吗?不代表成功。

有3个状态 :pendding:正在执行的状态,new Promise的时候会形成此状态

resolve【fulfilled】成功的状态 =》 resolve()

rejected:失败的状态 => reject()

 

3.then和catch方法

then的回调函数接收的是成功的结果

catch的回调函数接收的是失败的结果

代码案例:

 let pro = new Promise( function (resolve,reject1){  
setTimeout( ()=>{
// resolve( 40000) //调用resolve 会改变为成功的结果
reject1( '此用户离职了' )
} ,1000)
} )


// pro.then(res=>{
// console.log(res,'1234')
// })
pro.catch(err=>{
console.log( err,'我是错误信息,而且非常友好的不报红' );
})
console.log( pro );

 

4.链式调用

代码案例:

    let pro = new Promise( function (resolve,reject1){  
setTimeout( ()=>{
resolve( 40000) //调用resolve 会改变为成功的结果
//reject1( '此用户离职了' )
} ,1000)
} )


pro.then(res=>{ //promise对象支持链式调用。先catch后写then也是可以的。
console.log(res,'1234')
}).catch( err=>{
console.log(err,'我是错误信息')
} )

 

5.then和catch这两个方法都会返回promise对象

  //此案例了解即可。
let pro = new Promise( function (resolve,reject1){
setTimeout( ()=>{
resolve( 40000) //加20000
} ,1000)
} )


pro.then(res=>{ //promise对象支持链式调用。先catch后写then也是可以的。
//相当于获取到了 员工A的工资。40000

return res + 20000
}).then( res2=>{
//要扣20%的税
console.log( res2,'上个then回调return过来的结果' );
} )

 

//此案例了解即可。
let pro1 = new Promise( function (resolve,reject1){
setTimeout( ()=>{
resolve( 40000) //员工的薪金
} ,1000)
} )

let pro2 = new Promise( function (resolve,reject1){
setTimeout( ()=>{
resolve( 10000) //是要加的钱
} ,1000)
} )


pro1.then(res=>{ //promise对象支持链式调用。先catch后写then也是可以的。
//相当于获取到了 员工A的工资。40000

return pro2
}).then( res2=>{ //这个then是pro2的then。所以拿到结果是pro2的resolve传递过来的数据
console.log( res2,'' )
} )

 

6.应用 ajax与promise封装

代码案例:

<script src="https://cdn.bootcdn.net/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

<script>

function Http( { url,method='get',data={} } ){
// { url,method='get',data={} } = { method:'post',url:'api.com' }
//console.log( url,method,data );
//return
return new Promise(( resolve,reject )=>{
$.ajax({
url, //请求的地址
method,//请求的方法
data,//传递的参数
success(res){
resolve( res ) //成功的回调
},
error(err){
reject(err) //失败的回调
}
})
})
}

Http( {
url:'http://api2.xqb.ink/api/courses'
} ).then( result=>{
console.log( result,'我是数据' )
} )

//Http( { method:'post',url:'api.com' } )
</script>

 

7.Promise.all()

该方法用于将多个 Promise 实例,包装成一个新的 Promise 实例

代码案例:


 

五、async函数

async函数本质上就是 Generator 函数的语法糖。

真正意义上的解决异步回调问题的方案,可以用同步的写法去写异步代码。

async函数可以自动的拿到promise的then的结果。我们连then都不用使用。

如果你的业务本身就没有使用ajax或者说没有异步,那么就没有必要使用promise和async

语法:

async function methodName (){

}
async ()=>{
可以使用await关键字。 await翻译过来是等待的意思 。
let result1 = await 后面要跟一个promise对象 //
let result2 = await 后面要跟一个promise对象 //
}
{
async fn(){

}
}

bnt.onclick = async ()=>{

}

 

1.async函数和await基本用法

代码案例:

let pro = new Promise( (resolve,reject)=>{

setTimeout( ()=>{
console.log(333)
resolve(1111)
} ,1000)

} )


//await is only valid in async functions and the top level bodies of modules
async function fn(){
console.log(1)
let result1 = await pro //await 是等待。等待pro.then 传递过来的结果赋值给result1
console.log( result1 ); //1111
console.log(2) //打印顺序:1 333 2
}

fn()

 

3.应用

解决回调地狱

代码案例:

<script src="https://cdn.bootcdn.net/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="./toos.js"></script>
<script>

//http://api2.xqb.ink/api/courses
//打开这个页面就要请求课程列表 ,拿到数据然后渲染页面。

async function renderCourseList(){
let result = await Http({
url:'http://api2.xqb.ink/api/courses '
})

console.log( result,'完事了' );
//后面省略n行代码
}


renderCourseList()

</script>

 

posted @ 2021-05-07 22:18  一花一世界111  阅读(121)  评论(0)    收藏  举报