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 = [
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>

浙公网安备 33010602011771号