ES6新特性
ES6发行自2015年,主要的新特性包括:模块化、面向对象语法、Promise、箭头函数、let、const、数组解构赋值等等(还有Async/await 关键字)
let、const关键字;变量解构赋值;模板字符串
let关键字(最好用let替代var)
-
和var一样,可以初始化多种类型的变量(数字、字符串、数组、对象),同var
-
块级作用域,作用域外不可被引用,同var
-
不存在变量提升,变量创建前,使用变量会报错(但是var可以,会取到undefined)
-
不会影响作用域链,按照js执行顺序执行,同var
//let可以初始化不限类型的变量
let a = 1;
let b,c,d;
let e = [];
let times = new Date;
console.log(times)
//3.不存在变量提升
console.log(ee)//undefined
var ee = 114
console.log(ww)//报错
let ww = 514
const关键字(常量)
-
const关键字是“常量”
-
const变量名默认要大写,例如const PI=3.14
-
对于简单数据类型的const变量,不允许修改,修改会报错。但是对于数组和对象类型的变量,没有这一项约束
变量的解构赋值
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构赋值。
-
数组对多变量赋值:
//数组的解构赋值
const arr = ['张学友', '刘德华', '黎明', '郭富城'];
let [zhang, liu, li, guo] = arr; -
对象对多变量赋值
//对象的解构赋值
const lin = {
name: '林志颖',
tags: ['车手', '歌手', '小旋风', '演员'],
drive = function(){
alert("drive my Tesla")
}
};
let {name, tags, drive} = lin;//分别赋值到字符串、数组、函数
模板字符串(``超级字符串)
在这章节内容里,我会使用传荣字符串型和``模板字符串做对比
-
支持多行内容
,内容里可以直接出线换行符(string只能用转义符号或者字符串拼接做到这一点) -
方便的变量拼接 ,使用
${变量名}xxx
即可实现变量拼接(比String的加号好用)
//1.支持多行
let str1="string只能输出一行内容口牙"
let sstr1=`Super字符串
想写几行就写几行
<ul>
<li>爽!</li>
</ul>`
//2.方便的字符串拼接
let newStr1 = "New "+str1
let superPlus = `New ${str1} Day`
简化的对象写法
ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。
注意:对象简写形式简化了代码,所以以后用简写就对了
let name = '尚硅谷';
let slogon = '永远追求行业更高标准';
let improve = function () {
console.log('可以提高你的技能');
}
//属性和方法简写
let atguigu = {
name,
slogon,
improve,
change() {
console.log('可以改变你')
}
};
箭头函数fn=()=>{}(重点)
-
箭头函数 this
指向声明时所在作用域下 this 的值
(这条非常重要) -
函数不能作为构造函数实例化
-
不能使用 arguments
-
如果形参只有一个,则小括号可以省略
-
函数体如果只有一条语句,则花括号可以省略,函数的返回值为该条语句的执行结果
//箭头函数和普通函数对比
let fn = function(e){
console.log(this)
console.log(e.target)
}
let fn_plus = (e)=>{
console.log(this)
console.log(e.target)
}
//1.箭头函数和普通函数this的指向不同
buttons = document.querySelectorAll("button")
buttons[0].addEventListener("click",fn) //返回调用这个函数的对象
//返回<button>111</button>
buttons[1].addEventListener("click",fn_plus) //返回函数在声明时所在作用域的对象
//返回window对象,要定位到调用这个函数的元素,需要用e.target
//两种简写情况
////只有一个形参,可以省略小括号
let plusme = a=>{return a+a}
////只执行一条语句,可以省略大括号和return
let addTwo = (a,b)=> a+b;
//两种不能这么写的情况
let fn2 = ()=>{
//arguments存储了 函数传递过来的所有实参,但是在箭头函数里不能这么写
console.log(argument.length)
}
let Person = (name,age)=>{
//构造函数的写法是这样,但是箭头函数不能用来写箭头函数
//报错信息:Person is not a constructor
this.name = name
this.age = age
}
let zhang3 = new Person("ZhangSan",23)//会报错
箭头函数适合与this无关的回调.定时器,数组的方法回调 箭头函数不适合与this有关的回调.事件回调,对象的方法
rest参数...args
它是用来替代箭头函数中无法使用arguments的问题的,但是需要注意一点,它只能放在形参中的最后一项
//rest 参数必须是最后一个形参
function minus(a,b,
... 拓展运算符
...扩展运算符能将『数组」转换为逗号分隔的『参数序列」
可以用于函数传参与展开对象
//1.拓展运算符可以向函数传递多个参数
let someList =[1,2,3,4]
let fn = (
Symbol一种新的不可运算的数据类型
Symbol是一种不可修改的数据类型,属于js语言中第七种基本数据类型
七种数据类型依次为:Undefined 、String 、Symbol 、Object 、Null 、Number 、Boolean
口诀:USONB (you are so NB) | ||
---|---|---|
U | undefined | |
S | string | symbol |
O | object | |
N | null | number |
B | boolean |
-
创建Symbol
//创建symbol的两种方法
////比较搞笑的是,s2不等于s3,因为初始化方法不一样
let s2 = Symbol('尚硅谷');
let s3 = Symbol.for('尚硅谷');
//symbol变量的内容和类型
console.log(s2, typeof s2); //Symbol(尚硅谷) 'symbol'
-
在对象中使用Symbol函数
好处在于使用symbol封装的函数非常安全
//Symbol是一个独一无二的值,这是给对象添加属性的示例
let game = {}
let method = {
up:Symbol(),
down:Symbol()
}
//symbol为对象内函数赋值
game[method.up] = function(){
console.log("我可以改变形状")
}
game[method.down] = function(){
console.log("我可以快速下降")
}
console.log(game)//我靠,咋用啊这个
//symbol为对象赋值的另一个例子
let youxi = {
name:"狼人杀",
// say : function(){console.log("speak something")}
// 由于Symbol是一个表达式,所以这种场景应该加上中括号
[Symbol('say')]:function(){
console.log('say something')//我靠,咋用啊这个
}
}
//Symbol内置属性:可以起到一个拓展对象功能的作用
const arr2 = [4,5,6];
arr2[Symbol.isConcatSpreadable]=false;
迭代器 Symbol(Symbol.iterator):
任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。经过观察,每一个可以迭代的对象都有一个这个属性:Symbol(Symbol.iterator):
ƒ values()
原生具备 iterator 接口的数据(可用 for xxx of
遍历)
真别写成for xxx in 了
Array | Arguments | Set | Map | String | TypedArray | NodeList |
---|
让我们仿照迭代器的工作原理,自己写一个迭代器
const banji = {
name: "医信一班",
stus: ['jim','bob','mike','jenny'],
[Symbol.interator](){
//索引变量
let index = 0
//this纸箱banji这个对象
let _this = this
return{
next:function(){
//如果索引值小于数组长度
if (index< _this.stus.length){
const result = {value:_this.stus[index], done:false}
//下标自增
index++
//返回结果
return result
}else{
return {value:undefined ,done:true}
}
}
}
}
}
//现在可以遍历这个对象了
//我真是活见了赛博幽灵了,为什么in 和 of关键词不一样啊
for (let v of banji){
console.log(v)
}
生成器
生成器其实就是一个特殊的函数,它有以下几个特点
-
星号要放在函数关键字和函数名中间,只要放在中间就行
-
yield是函数代码的分隔符,它将函数代码分割成几部分
-
调用时返回一个迭代器对象,使用.next()方法执行下一步
//生成器其实就是一个特殊的函数
//对于异步编程来说,function都是纯回调函数,例如node fs ajax mongodb
//1.星号要放在函数关键字和函数名中间,只要放在中间就行
//2.yield是函数代码的分隔符,它将函数代码分割成几部分
function *gen(){
console.log(111);
yield '一只没有耳朵';
console.log(222);
yield '一只没有尾部';
console.log(333);
yield '真奇怪';
console.log(444)
}
//执行结果比较特殊,会返回一个迭代器对象,而不是里面的语句
let iterator =gen();
console.log(iterator)//会输出一个迭代器对象
iterator.next();//111,只有使用next方法才能让它继续执行
iterator.next();
iterator.next();
iterator.next();
//一种遍历方法
for(let v of gen()){
console.log(v);
//111 '一只没有耳朵' ...
}
生成器是可以传参的
具体的在于,只有进行第一次next().后,才会执行函数体内语句
但是第二次next(参数).就可以携带参数到第一个yield里面了,见例子:
function *gen(a){
console.log("begin");
console.log(a)
let one = yield '这里写啥其实不重要对吧';
console.log(one);
let two = yield '看不见';
console.log(two);
}
//这里传参,是可以的,但是函数不会开始执行,需要一个next让生成器启动
let iterator = gen('AAA');
//第一次next不要传参,它相当于启动按钮,一直执行到下一个yield
iterator.next();
//第二次next可以开始传参了
iterator.next("n1");
iterator.next("n2");
//多写一个next实际上是没用的,什么也不会发生
//next数目应该等于 yield+1
iterator.next("n3");
生成器应用(简单的异步操作,按顺序执行)
在开发过程中,我们很有可能遇到多个异步操作,其中的嵌套关系非常复杂,这时候我们可以用生成器理清他的关系。
这个场景在于,实际开发中,下一步是由获取到前一步的参数为前提的,也就是前一步完成后才能触发下一步
//多个回调函数嵌套在一起,嵌套关系很混乱,我们不要这样子
// setTimeout(()=>{
// console.log(111);
// setTimeout(()=>{
// console.log(222);
// setTimeout(()=>{
// console.log(333)
// },3000);
// },2000);
// },1000) //111 222 333
//试着用生成器按步骤执行的特定重写一下异步函数
function one(){
setTimeout(()=>{
console.log(111);
//由第一个函数执行成功后,启动第二个函数
iterator.next();
},1000)
}
function two(){
setTimeout(()=>{
console.log(222);
iterator.next();
},222)
}
function shree(){
setTimeout(()=>{
console.log(333)
},333)
}
//设置生成器,由第一个函数用next触发第二个函数,以此类推
function *gen(){
yield one();
yield two();
yield three();
}
//让生成器启动
let iterator = gen();
iterator.next();
Promise(重点)
在没有promise之前,我们都用上面的生成器的方案来执行异步操作,有了promise后,情况就大为改观了。
在语法上promise是一个构造函数,用来封装异步操作并可以获取器成功或者失败的结果。
当正确执行异步操作时,使用resolve()以进入到then的成功状态,执行异步操作失败时,使用reject()以进入到then的失败状态
//实例化的时候,接收一个函数类型的值,接受两个形参(默认形参名为:resolve,reject)
////函数体里面封装一个异步的操作
const p = new Promise(function(resolve,reject){
setTimeout(function(){
let data = '数据库中的用户数组'
//当调用玩resolve函数后,p的状态就会为成功(promise的三种状态:初始化/成功/失败)
resolve(data)
// let err = "数据读取失败了啊啊"
// //当调用reject函数后,p的状态就会为失败,同时进入到then方法中
// reject(err)
},1000)//
});
//当p的状态为成功/失败后,就可以进入到then方法中
////then方法的形参是两个函数,成功函数放在第一个的形参是value,失败函数放在第二个的形参是reason
p.then(function(value){
//value是resolve传递来的值
console.log(value);
},function(reason){
//reason是reject传递来的值
console.log(reason)
})
Promise的链式调用
调用then方法 then方法的返回结果是Promise对象,对象状态由回调函数的执行结果决定 如果回调函数中返回的结果是非promise类型的属性,状态为成功,返回值为对象的成功的值
//创建promise对象
const p = new Promise((reslove,reject)=>{
setTimeout(()=>{
// reslove('用户数据调用成功');
reject("ERR Occure")
},1000)
})
//then
let result = p.then(value =>{
console.log(value);
// return 123
},reason=>{
console.warn(reason);
//throw 'AAA'//这个会抛出一个自定义报错,相当于python里的raise
})
console.log(result) //不管then有没有返回值,都会返回resolve()或者reject()里面携带的内容
基于then函数会返回一个promise对象的特性,我们可以写出promise的链式调用
//链式回调
p.then(value=>{
//这里可以再写一个promise
}).then(value=>{
}).then(value=>{
//每个then执行完后,反正是一个Promise对象,因此可以一遍又一遍的嵌套异步操作
})
catch语法糖
catch和then的用法一样,是专门用来捕获promise异步错误的
//创建promise对象
const p = new Promise((reslove,reject)=>{
setTimeout(()=>{
// reslove('用户数据调用成功');
reject("ERR Occure")
},1000)
})
p.then(function(value){},function(reason){})
p.catch(function(reason){
console.warn(reason)
})
Set集合
-
集合Set基本操作
//声明一个 set
let s = new Set();
//集合set初始化时,可以接受传入一个可迭代数组
let s2 = new Set([1,5,2,1,3,6,5])
console.log(s2,typeof(s2))//会自动帮你去重
//元素个数
console.log(s2.size)
//添加新的元素
s2.add(14)
//删除元素
s2.delete(6)
//检测,存在输出true、不存在输出flase
s2.have(5)
s2.have(114514)
//清空
s2.clear
//遍历(使用for xxx of)
for(let v of s2){
console.log(v);
}
-
集合Set进阶操作
去重、交并差集
//1.数组去重
let arr = [1,3,5,7,9,9,5,3,1]
let result = [
Map
Map数据结构它类似于对象,键值对的集合。但是“键”不限于字符串,可以是各种数据类型。
并且集成了。。。可以使用for of进行遍历
let m = new Map();
// 添加元素
////这三个例子是想告诉你,map的set方法,键可以是任何是数据类型,值可以是数据或者函数
m.set('name','尚硅谷')
m.set('change',function(){
console.log("66666")
})
let key={
school:'ATGUIGU'
}
m.set(key,['Shanghai','Beijing'])
// size 显示map长度。 m.size>>>3
//删除
m.delete('name')
//清空
m.clear()
//查询
m.get('change') //输出一个函数
m.get(key) //可以使用对象作为键,查询值
class
class介绍与初体验
传统方法写构造函数
//传统方法写构造函数
function Phone(brand,price){
this.brand = brand;
this.price = price
}
//添加构造函数的方法,建议使用原型对象进行添加,这样可以做到重用
Phone.prototype.calling = function(){
console.log("I can call via my phone")
}
//实例化对象
let Huawei = new Phone("Huawei",5999)
Huawei.calling(); //调用函数成功
class方法写构造函数(constructor
)
//class方法写这个函数
class Phone{
//构造方法,名字是固定的,会在使用new Phone的时候自动执行
constructor(brand,price){
this.brand = brand;
this.price = price;
}
//class里面必须使用标准的函数写法,支持箭头函数
calling(){
console.log(666666)
}
// calling = ()=>{
// console.log(77777)
// }
}
let Huawei = new Phone("Huawei",5999)
Huawei.calling(); //调用函数成功
class静态方法
静态对象的定义:
//传统的函数静态对象,示例对象,是没有构造函数对象那样的属性的
function Phone(){
}
Phone.name="手机";
Phone.change = function(){
console.log(66666)
}
let nokia = new Phone();
console.log(nokia.name) //undefined (即实例对象nokia的属性和静态对象Phone不通用)
//如果想通用的话,用Phone.prototype.name="手机";
class实现静态对象 static
对于static标注的方法,它属于类但是不属于实例对象
class Phone{
//静态属性
static name = '手机';
static change(){
console.log("change the world")
}
}
//实例化对象,发现无法使用类里面的静态属性
//对于static标注的方法,它属于类但是不属于实例对象
let nokia = new Phone()
console.log(nokia.name)
console.log(Phone.name)
构造函数实现继承
ES5中有构造函数的继承,主要步骤有二:
//使用call方法改变this的值,此时this指向SmartPhone的实例对象 Phone.call(this,brand,price)
//这样子级构造函数的实例对象,里面就会有父级的方法 SmartPhone.prototype = new Phone;
//父级构造函数
function Phone(brand,price){
this.brand = brand;
this.price = price
}
//添加构造函数的方法,建议使用原型对象进行添加,这样可以做到重用
Phone.prototype.calling = function(){
console.log("I can call via my phone")
}
//子级构造函数
function SmartPhone(brand,price,color,size){
//使用call方法改变this的值,此时this指向SmartPhone的实例对象
Phone.call(this,brand,price)
this.color = color;
this.size = size;
}
//设置子级构造函数的原型prototype
//这样子级构造函数的实例对象,里面就会有父级的方法
SmartPhone.prototype = new Phone;
//对子级构造函数的构造器做一个矫正(下面这行代码不加也不会影响)
SmartPhone.prototype.constuctor = SmartPhone;
//声明子类对象的方法
SmartPhone.prototype.photo = function(){
console.log("I can take a picture")
}
//实例化对象
const chuizi = new SmartPhone('锤子',2499,'black','ProMax')
console.log(chuizi)
类的继承
//super函数以调用父类中的方法(究极方便啊) super(brand,price)
class Phone{
//构造方法
constructor(brand,price){
this.brand = brand;
this.price = price;
}
//父类的成员属性
calling(){
console.log("I can calling for you")
}
}
//用extend继承父类中的方法
class SmartPhone extends Phone{
//构造方法
constructor(brand,price,color,size){
//super函数以调用父类中的方法
super(brand,price)
this.color = color;
this.size = size;
}
//子类里独有的方法
photo(){
console.log(6666666)
}
}
const Xiaomi = new SmartPhone('Xiaomi',1999,'blue','4.7inch')
console.log(Xiaomi)
Xiaomi.calling()
Xiaomi.photo()
如果子类和父类有同名方法的话,子类的方法会覆盖掉父类的方法,称之为“子类对父类的方法重写”
Class里的get 和set
-
当对某一属性进行获取时,执行get price函数里面的代码(应用场景:实时修改数据)
-
当对某一属性进行设置时,执行set price方法里的函数(应用场景:表单输入数据合法判断)
//class类里的get和set
// 当对某一属性进行获取时,执行get方法里面的函数
// 当对某一属性进行设置时,执行set方法里的函数
class Phone{
//只要price属性被读取,就执行get price函数里面的代码,且这个函数里面的返回值,就是这个price属性的值
get price(){
console.log('价格属性被读取了')
return 114514
}
// 只要price属性被修改,就执行set price函数里面的代码
set price(whatever){
//值得注意的是,这个函数必须调用一个参数
console.log('价格属性被修改了')
}
}
//实例化对象
let s = new Phone();
console.log(s.price);
s.price = 'free'
console.log(s)
ES6里的数值拓展
- Number,EPSILON是JavaScript表示的最小精度 EPSIL0N属性的值接近于2.2204460492503130808472633361816E-16 主要用于浮点数近似相等
function equal(a,b){
//判断两数差值是否小于最小精度,小于则判断为相等
if(Math.abs(a-b)<Number.EPSILON){
return true;
}else{
return false;
}
}
conso1e.log(0.1+0.2==0.3);//false
conso1e.log(0.1+0.2,0.3);//true - 二进制和八进制
let b = 0b1010; //2进制,10
let o = 0o777; //8进制,511
let d = 100; //10进制,没什么好说的
let x = 0xff; //16进制,512 - Number.isFinite 检测一个数值是否为有限数
- Number,isNaN检测一个数值是否为NaN Number.isNaN(123)//输出false,表示不是NaN,是一个数
- Number.parseInt Number.parseFloat字符串转整数
- Number.isInteger判断一个数是否为整数
- Math.trunc将数字的小数部分抹掉
- Math.sign判断一个数到底为正数负数还是零 (返回1、0、-1)
ES6里对象方法的拓展
-
Object.is 判断两个值是否完全相等
和全等号===很像
-
Object.assign
对象的合并Object.assign(对象1,对象2) //并集,如果属性重名,后面的对象会把前面的对象属性值覆盖掉
-
Object.setprototypeOf 设置原型对象 Object.getprototypeOf (效率不高,一般不用)
ES6模块化import
模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来
-
模块化的好处
1.防止命名冲突
2.提高代码复用性
3.高维护性
模块化主要由以下两个命令:
-
export
:主要用于规范模块的对外接口(暴露到外面) -
import
:用于输入其他模块提供的功能(引入别人的功能)
模块化(暴露export和引用import)
js文件里面写模块暴露:
-
分别暴露,在变量名前加关键词‘export’
-
集中暴露,export{变量名1,变量名2}
-
默认暴露,export default{ 里面写好变量初始化语句,变量、方法、对象都统一暴露出去}
//在需要暴露的对象前加‘export’
export let school = '尚硅谷'
export function teach(){
console.log(666)
}
//集中暴露(用大括号把变量名围起来)
export {school,teach}
//默认暴露,在export default {}内写上数据,会自动全部暴露出去
////这就是vue2所使用的啊!!!太棒了
export default {
//默认暴露,所有变量都存在default变量下面
school: 'ATGuiGu',
change: function(){
console.log(5666666)
}
//可以是任意类型的
}
html标签中写模块引用,全部返回数据存储在m1这个变量里面
-
通用引入(通用,import {变量名} from '文件地址')
-
解构赋值引入(对应默认暴露default以及重名的引用变量名)
-
简便引入(只能针对默认暴露)
<script type="module">
//1.通用的导入方式
//将m1.js里面所有暴露的变量,全都输出到变量m1里面了
import * as m1 from "./src/m1.js"
console.log(m1)
//2. 解构赋值形式(对应分别暴露)
import {school,teach} from './src/m1.js'
//// 可以命名以防止重名
import {school as guigu,teach} from './src/m1.js'
//3. 对应默认暴露,默认暴露所有变量都存储在m3下面,我们对default做一个别名设置
//// 记住,不能直接使用default,必须取一个别名
import {default as m3} from "./src/m1.js"
//4. 简便暴露(只能针对默认暴露)
import m3 from "./src/m1.js" //效果同上
</script>
ES6里面引入模块的新方法(一次性全引入)
html文件中:
<script src="./src/m1.js" type="module"> </script>
js文件中
import * as m1 from './src/m1.js'
import * as m2 from './src/m2.js'
import * as m3 from './src/m3.js'
//不用写export,html直接引入这个文件,就相当于依次执行了以上语句,非常方便且统一化
ES6模块化代码在项目中使用(使用babel将ES6语法转换为ES5)
由于ES6的import方式并不支持npm的一些库的一键引入,并且为了IE、火狐等浏览器的兼容性,我们一般会使用
-
安装工具 babel-cli(babel命令行工具) babel-env(预设包,能够把最新的ES特性转换为ES5) browserify(webpack替代品,做项目打包) npm i babel-cli babel-env browserify -e (为当前项目安装)
-
终端下使用 npx babel src -d dist/js --preset=base-preset-env 文件的目录 -d 存到哪个文件夹下 跟一个参数 3.源文件下js文件是原先的,dist文件夹下是babel转换后的结果
-
打包 npx browserify dist/js/app.js -o dist/bundle.js
<!--
1. 安装工具 babel-cli(babel命令行工具)
babel-env(预设包,能够把最新的ES特性转换为ES5)
browserify(webpack替代品,做项目打包)
npm i babel-cli babel-env browserify -e (为当前项目安装)
2. 终端下使用
npx babel src -d dist/js --preset=base-preset-env
文件的目录 -d 存到哪个文件夹下 跟一个参数
3.源文件下js文件是原先的,dist文件夹下是babel转换后的结果
4. 打包
npx browserify dist/js/app.js -o dist/bundle.js
-->
<script src="dist/bundle.js"></script>
juqery包导入
app.js里面这样写:import $ from 包名
//修改背景颜色为粉色
//这是一个固定写法:import $ from 包名
import $ from 'jquery';//const $ = require("jquery");
$('body').css('background','pink');
然后依次执行:npx babel src -d dist/js --preset=base-preset-env
npx browserify dist/js/app.js -o dist/bundle.js
最后在html里面导入dist/bundle.js文件即可
ES7新功能(**幂运算和检测数组中存在某元素)
-
includes
//includes
const mingzhu = ['西游记','红楼梦','水浒传','三国演义']
console.log(mingzhu.incudes['西游记'])//true -
幂运算 2**3=8
效果相当于Math.pow(2,3)
Async await 异步函数
初识Async
-
Async函数的返回值是promise对象
-
Promise的语法结构是Promise(function(resolve,reject){xxx}),promise里面是一个函数,切记
//写法就是在普通的函数前面加上async关键字,这样函数就会返回一个promise对象,如果返回的不是promise类型,也认为是promise成功状态。
////有助于方便的触发then函数
async function fn(){
//throw抛出错误,结果是一个失败的promise
////throw new Error('出错啦')
return new Promise(function(resolve,reject){
// resolve('成功的数据')
reject('失败的数据')
})
}
const result = fn();
console.log(result)
//调用then方法
result.then(value =>{
console.log(value)
},reason=>{
console.log("ERR: ",reason)
})
await表达式
-
await必须写在async函数中
-
await右侧的表达式一般为promise对象
-
await返回的是promise成功的值
-
await的promise失败了,就会抛出异常,需要通过try...catch捕获处理
//创建Promise对象
const p = new Promise((resolve,reject)=>{
// resolve('success')
reject('ERROR')
})
//await要放在async函数中
async function fn2(){
try{
//await返回的是promise成功的值
let result = await p;
console.log(result)
}catch(e){
//await的promise失败了,就会抛出异常,需要通过try...catch捕获处理
console.log(e)
}
}
//切记要调用async函数
fn2()
用async实现Ajax请求
//发送AJAX请求,返回的结果是Promise对象
function sendAJAX(url){
return new Promise((resolve,reject)=>{
//1.创建对象
const x = new XMLHttpRequest();
//2.初始化
x.open('GET',url)
//3.发送
x.send()
//4.事件绑定
x.onreadystatechange = function(){
if(x.readyState ===4){
if(x.status >= 200 && x.status<300){
//成功啦
resolve(x.response);
}else{
//如果失败
reject(x.status)
}
}
}
})
}
//测试,能拿到结果,且是一个Promise对象
// console.log(sendAJAX('https://api.apiopen.top/getJoke'))
//Promise。then方法
// sendAJAX('https://api.apiopen.top/getJoke').then(value=>{
// console.log("success!: ",value)
// },reason=>{
// console.log("ERR: ",reason)
// })
//async,await方法
////用AJAX发请求,用await接请求,实在是非常方便啊
async function fn(){
//发送AJAX请求,刚好await右侧需要一个promise对象
let result = await sendAJAX('https://api.apiopen.top/getJoke')
console.log(result)
}