欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ES6入门

程序员文章站 2022-07-05 14:00:45
...

let和const

回顾 var和function

var会把变量声明提前,但是定义没有提前;function会把声明和定义都提前;全局作用域下:使用var和function声明的变量会给window增加属性

  getA();
  console.log(a);
  var a=1;
  function getA(){
    console.log("方法执行");
  }
  输出:"方法执行"  underfined

let

区别:① 没有变量声明提升 ② 不可以重复定义 ③ 不会把该变量添加到window上面

  console.log(a);
  let a=0;
  console.log(window.a);
  let a=0;
  说明:都会报错,分别针对上面的几种情况

const

区别:也满足let的三者区别,还包含① 一旦声明必须赋值
② 一旦赋值不可以修改(但是内部的引用数据可以修改)

  const a={"a":1,"arr":[1,2,3]};
  a.arr[2]=5;
  console.log(a.arr); //[1,2,5]

作用域

es6之前只有全局作用域和私有作用域,es6添加了块级作用域

块级作用域

凡是{}都是块级作用域,在块级作用域下,var和function声明的变量依然是全局的,但是let和const声明的变量是私有的

{
  var a=0;
  let b=0;
}
console.log(a); //0
console.log(b); // b is not define

块级作用域使用

注意:{}如果想表示一个对象,不能放在行首,否则就要用()包裹或者变量接收,不然会被当成一个块级作用域

({"name":"info"});
块级作用域的:if(){}
if(){}中的函数只会提前声明不会定义,当条件成立才会定义

console.log(getA,a);  //undefined undefined
if(0){
  var a=1;
  function getA(){}
}
console.log(getA,a); //undefined undefined


console.log(getB,b);  //undefined undefined
if(1){
  console.log(getB,b); //ƒ getB(){} undefined
  var b=1;
  function getB(){}
}
console.log(getB,b); //ƒ getB(){} 1

说明:块级作用域内部的函数声明和定义被提升到块级作用域的最上部;但是块级作用域内部的变量只是声明被提升到块级作用域的最上部。

块级作用域的:for(){}
let func=[];
for(let i=0;i<10;i++){
  func.push(function(){
    console.log(i);
  })
}
func[5](); //5

var funcv=[];
for(var i=0;i<10;i++){
  funcv.push(function(){
    console.log(i);
  })
}
funcv[5](); //10

说明:对比上面两套代码得出结论,let在for(){}中使用,
每一次循环都是一个私有的作用域,互不影响;

解构赋值

数组的解构

设置默认值,如果后面是underfined则会指定默认值的相关操作,如果不是underfined(即使是null等也不行)则执行默认值操作

let a=[1,2,3,4];
let [b,c,...d]=a;
console.log(b,c,d);//1 2 [3, 4]
let [x1,x2=10]=[1,2]
console.log(x1,x2); //1,2
//省略赋值
let [,y]=[1,2];
console.log(y);//2

对象的解构赋值

数组解构赋值有顺序,对象解构赋值可以没有顺序

// let {name,age=10}={name:"qiang",age:undefined};
//{name:name}第一个name是属性值,第二个name才是变量名
//使用的都是变量名,而不是属性值
//值是undefined时候,使用默认值
let {name:name,age=10}={name:"qiang",age:undefined};
console.log(name,age); //qiang 10
//嵌套
let {list:[a,b,c]}={list:[1,2,3]};
console.log(a,b,c);//1 2 3  此时list是属性名而不是变量名,a,b,c才是变量名

其他数据类型解构赋值

//使用数组的解构赋值的形式,如果等号右边不是一个数组,默认将其转换为类数组(类似数组的对象,必须有length属性)
let [x,y]="123";
console.log(x,y);//1 2 都是字符串
//使用对象的解构赋值的形式,如果等号右边不是对象,默认转为对象
console.log(Object(1)); //Number {1}__proto__: Number[[PrimitiveValue]]: 1
let {a}=1;
console.log(a);//underfined
let {__proto__:b}=1;
console.log(b);//输出一个Number类型的对象
let {length:c}="123";//其实这个length就是 Object("123")打印之后对象的一个属性
console.log(c);//3

函数参数的赋值

function getA({name,age=10}){
    console.log(name,age);
}
function getA1({name,age=10}={}){
    console.log(name,age);
}
 getA("qiang");//undefined 10
 //这样直接调用getA函数,就相当于传递了underfined,但是underfined是没有name和age属性的
 //解决方案是如getA1={}一样赋一个空对象当作默认值
 getA();//报错


 function getA2({name="qiang",age=20}={}){
    console.log(name,age);
}
function getA3({name,age}={name:"qiang",age:20}){
    console.log(name,age);
}
getA2();//qiang 20
getA3();//qiang 20
getA2({});//qiang 20
getA3({});//undefined undefined
说明:对比这四个结果,分析区别。

字符串扩展

//1.includes  返回值布尔
//includes("指定字符",开始查找的位置(可选))
//第二个参数不是一个数字的话,就使用Number转换,例如null=>0
console.log("abs".includes('a',1));//false
//2.startswith endswith
//startswith("指定字符",开始查找的位置(可选)),参数二如果不是数字同上
console.log("anc".startsWith('a',0));//true
//endswith("指定字符",从前几个查看(可选)),参数二同上
console.log("anc".endsWith('c',2));//false
//3.repeat 重复,参数必须取整,不可以负数或者Infinity
console.log("abc".repeat(4));//abcabcabcabc
//4.padStart  padEnd  ES7
//按照指定,补全字符串的指定长度
//参数一:长度,参数二:指定字符
let str="ab";
console.log(str.padStart(5,'g'));//gggab
console.log(str.padEnd(5,'gg'));//abggg
//5.模板字符串
let a="abc";
console.log(`${a}测试`);//abc测试

数组的扩展

Array类上的扩展

//1.Array  是一个函数,返回一个数组
console.log(Array("abc"));//["abc"]
console.log(Array(1,2,3));//[1,2,3]
//如果只有一个参数,且是数字,返回有N个空位的数组
console.log(Array[7]);//[empty*7] 得到七个空位
//Array.of和Array等效,除了在只有一个数字参数时候返回的还是数组
console.log(Array.of(7));//[7]
//Array.from(数组/类数组(有length属性)) 返回一个数组
console.log(Array.from("abc"));//["a","b","c"]

数组原型上的扩展

//1.copyWith 从原数组中读取内容,替换数组的指定位置的内容,修改的是原数组
//(替换目标的起始位置target,查找的起始位置begin,查找的结束位置end(不包括))
let arr=[1,2,3,4,5,6,7,8];
// console.log(arr.copyWithin(4,2,4))// [1, 2, 3, 4, 3, 4, 7, 8]
// console.log(arr)// [1, 2, 3, 4, 3, 4, 7, 8]
//参数三:省略,会直接查找到最后,如果有超出部分,自动截取,原数组length不变
console.log(arr.copyWithin(4,5)) //[1, 2, 3, 4, 6, 7, 8, 8]
//2.fill 按照指定字符填充数组,修改原数组
console.log(arr.fill("呵呵"));// ["呵呵", "呵呵", "呵呵", "呵呵", "呵呵", "呵呵", "呵呵", "呵呵"]
console.log(arr.fill("111",3));//["呵呵", "呵呵", "呵呵", "111", "111", "111", "111", "111"]
//参数三:不包含
console.log(arr.fill("222",3,6));// ["呵呵", "呵呵", "呵呵", "222", "222", "222", "111", "111"]
//3.filter,过滤,返回一个新的数组
let arr1=[1,2,3,4,5,6];
let a1=arr1.filter((value,index,arr)=>{
    return value>4;
});
console.log(arr1);//[1,2,3,4,5,6]
console.log(a1);//[5,6]
//4.find  先遍历数组,一旦参数函数返回true,停止查找,返回当前项
//finindex 先遍历数组,一旦参数函数返回true,停止查找,返回当前项索引
let arr2=[1,2,3,4,5,6];
let a2=arr2.find(item=>{
    return item>4;
})
console.log(a2);//5
console.log(arr2.findIndex(item=>{
    return item>2;
}));//2
//5.includes 判断数组中有没有某一项
let arr3=[1,2,3];
console.log(arr3.includes(1));//true
console.log(arr3.includes(1,1));//false 参数二,是开始查找的位置
//6.reduce 迭代,回调函数参数一:上一次的值,参数二:当前值
console.log(arr3.reduce((pre,cur)=>{
    return pre+cur;
}));//6 第一次没有pre 会自动使用0
//7.reduceRight 和reduce一样,只是顺序从右边开始
//8.keys 遍历每一项的接口,可以使用for of/in中
//9.entries 遍历接口,可以遍历到索引和每一项
//10.补充
let arr=["a","b","c"];
arr.filter(function(item,index){
    console.log(this);//window
});
arr.filter(function(item,index){
    console.log(this);//arr
},arr);
arr.filter((item,index)=>{
    console.log(this);//window
});
说明:这种遍历类型的,即使使用箭头函数,也会this指向错误,所以可以通过第二种方式解决(recude和reduceRight不可行,因为这俩方法的参数二是指定默认值的)。

数组空位

数组空位:当前数组的某个索引位置没有任何值,underfined不是空位。判断空位,可以用in方法

//in 判断数组索引位置上有没有值
let arr=[,,,,];
console.log(arr.length);//4 此处是4而不是5,一个逗号代表一个空位
console.log(1 in arr);//false 1是索引
//es5中数组方法对空位的处理一般直接跳过空位 ,例如filter
//es6中方法奖空位处理为underfined
//题目:得到一个7个1的数组
console.log(Array(7).fill(1));

函数的扩展

//length指的是形参的个数,如果形参有默认值,就变成了形参没有默认值的个数
//一般参数的默认值放在最后面
function fn(x,y=4){}
console.log(fn.length)//1
//参数
function fn1(...arg){
    console.log(arg);//数组
    console.log(arguments);//类数组
}
fn1([1,2,3,4])

函数作用域问题

函数执行的时候先给形参赋值,形参也是私有变量,如果给形参的默认值也是一个变量,先看是不是自己的私有变量,不是自己的再找全局中是否有这个变量,没有就报错。
私有作用域:形参也是私有变量

let m=100,n=10;
function fn(x,y=x){
    console.log(x,y);
}
fn(1);//1 1

扩展运算符

  • 将非数组(类数组 length)变成数组
  • 将数组变成非数组
// 非数组=》数组
let str="123";
console.log([...str]); //['1','2','3']
// 数组=》非数组
let arr1=[1,2,3];
let arr2=[1,2,3];
console.log(arr1.concat(arr2)); //[1,2,3,1,2,3]
console.log([...arr1,...arr2]);//[1,2,3,1,2,3]
//求最大值
let arr3=[1,2,3,4,5];
console.log(Math.max(...arr3));//5
console.log(Math.max.apply(null,arr3)); //5

箭头函数

箭头函数都是匿名函数,通常函数当作参数情况下使用箭头函数

  • 箭头函数没有this指向,里面的this是上一级的作用域下的this,如果上一级仍然是箭头函数,继续向上找.
  • 箭头函数没有arguments
  • 箭头函数不可以用作构造函数,因为不可以用作new执行
let ojb={
   fn:function(){
       let fn=()=>{
           console.log(this);//{fn:f}
           console.log(arguments);//arguments is not defined
       };
       fn();
   }
}
ojb.fn() 

let ojb={
   fn:function(){
       let fn=function(){
           console.log(this);//windows
       };
       fn();
   }
}
ojb.fn() 

对象的扩展

对象的简洁方式

let name="qiang",age=20;
let info={name,age};
let str="hehe";
let obj={
    //fn:function(){} 
    fn(){}, //等效于上面
    //属性名是字符串,属性名使用[]里面可以写变量
    [str]:name,
    ["my"+str]:name,
    "str":name
}
console.log(obj.str,obj.hehe,obj.myhehe);//qiang  qiang qiang

Object的方法扩展

//1.Object ()将参数变成对象
console.log(Object(1));//Number {1}
console.log(Object(true));//Boolean {true}
//2.Object.is 判断两个值是否相等,除了下面两种,其他和===相同
//=== NaN跟NaN不相等 -0===0 true
console.log(Object.is(NaN,NaN))//true
console.log(Object.is(-0,0))//false

//3.Object.assign(obj1,obj2) 合并对象 把obj1合并到obj2上,返回obj1
let obj1={name:"qiang"};  
let obj2={age:12};  
let obj=Object.assign(obj1,obj2);
console.log(obj); //{name: "qiang", age: 12}
console.log(obj1);//{name: "qiang", age: 12}
//ES7提供了对象的扩展运算符... 如果属性重复,只保留一份
let a1={name:"hehe"};
let a2={info:"ascaa"};
let a={...a1,...a2};
console.log(a); //{name: "hehe", info: "ascaa"}

//4. Obejct.getOwnPropertyDescriptor 获取一个对象某个属性的描述
console.log(Object.getOwnPropertyDescriptor("123","length"));//{value: 3, writable: false, enumerable: false, configurable: false}

对象的get和set

let obj={
    _name:"AA",
    get name(){
        // console.log("获取");
        return this._name;
    },
    set name(val){
        // console.log("设置");
        // console.log(this==obj);//true
        this._name=val;
    }
}
console.log(obj.name); //AA
obj.name="测试";
console.log(obj.name);//测试
错误案例:
let obj={
    name:"AA",
    get name(){
        // console.log("获取");
        return this.name;
    },
    set name(val){
        // console.log("设置");
        // console.log(this==obj);//true
        this.name=val;
    }
}
obj.name="测试";
说明:这样会无限死循环,set利用是自己设置自己

Symbol

ES6新增的数据类型

//Symbol是一个新的基本数据类型,而且是一个值类型
//使用Symbol函数执行得到一个Symbol数据类型
//跟字符串差不多,但是使用symbol函数得到的数据任意一个都是独一无二完全不同的。
//symbol可以接受一个参数()是对symbol数据的一个描述
//symbol的值不可以跟其他值计算(加减乘除,凭借字符串等等,但是可以转为布尔值)
//作用:一般当作对象的属性
let sym1=Symbol();
let sym2=Symbol();
console.log(typeof sym1);//symbol
console.log(sym1===sym2);//false
let sym3=Symbol("foo");
console.log(sym3);//Symbol(foo)
// console.log(Number(sym3));//会报错
console.log(!Symbol());//false
console.log(Symbol().toString());//Symbol() 字符串

//获取
//Symbol.for() 如果之前有有相同描述的symbol找到这个值,如果么有就创建一个新的symbol
console.log(Symbol.for("foo"));//Symbol(foo)
//使用Symbol.for参数相同值就相同
let q1=Symbol.for("q");
let q2=Symbol.for("q");
console.log(q1===q2);//true,因为第一次是创建,第二次是得到,所以会相等
//Symbol.keyFor(symbol值):找到利用Symbol.for创建的值的描述
//如果使用的是Symbol创建的,利用Symbol.keyFor是得不到的,返回Underfined
console.log(Symbol.keyFor(q1)); 

Set

类似数组,只有值没有键.通过构造函数方式创建set实例,会默认去重(有size属性)

//参数是一个数组或者类数组(只要有iterable接口的数据:数组,arguments,元素集合,set,map,字符串)
console.log(new Set([1,1,2,3]));//Set(3) {1, 2, 3}
console.log(new Set(["111"]));//Set(1) {"111"}

let s=new Set([1,2,3]);
//size set实例的大小的个数
//add  增加,如果之前没有加上,有的话不加,返回增加后的set实例
//参数,一次只能加一个,不能添加多个
console.log(s.add(2)); //Set(3) {1, 2, 3}
//clear 清空
// console.log(s.clear());//underfined
//delete 删除,成功返回true,失败返回false
//has 判断有没有此项,返回布尔值
s.forEach((v1,v2,set)=>{
    console.log(v1); //v1 v2都是当前项,因为set没有key,set就是实例
});
//keys :遍历的接口 和for in/of搭配
//entries :遍历的接口 和for in/of搭配

Map

构造函数方式创建一个Map
参数是一个数组,数组每一项也是数组,有key和value
map实例的key可以是任意数据类型,这点和对象不同(对象的key必须是字符串,不是字符串会自动转成字符串)

// 一个对象,属性名必须是字符串,如果不是字符串,默认也会转成字符串
let m=new Map([[1,2],[3,4]]);
console.log(m);//Map(2) {1 => 2, 3 => 4}
//1.size
//2.get set has delete clear
//3.forEach keys values entries
let m1=new Map([[true,[{name:"name"},{age:12}]],[[1,2],"字符串"]])
console.log(m1);// {true => Array(2), Array(2) => "字符串"}

WeakMap和WeakSet

WeakSet 结构与 Set 类似,也是不重复的值的集合。但是,它与 Set 有两个区别。首先,WeakSet 的成员只能是对象,而不能是其他类型的值。
WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。
这是因为垃圾回收机制依赖引用计数,如果一个值的引用次数不为0,垃圾回收机制就不会释放这块内存。结束使用该值之后,有时会忘记取消引用,导致内存无法释放,进而可能会引发内存泄漏。WeakSet 里面的引用,都不计入垃圾回收机制,所以就不存在这个问题。因此,WeakSet 适合临时存放一组对象,以及存放跟对象绑定的信息。只要这些对象在外部消失,它在 WeakSet 里面的引用就会自动消失。
由于上面这个特点,WeakSet 的成员是不适合引用的,因为它会随时消失。另外,由于 WeakSet 内部有多少个成员,取决于垃圾回收机制有没有运行,运行前后很可能成员个数是不一样的,而垃圾回收机制何时运行是不可预测的,因此 ES6 规定 WeakSet 不可遍历。
WeakMap和WeakSet类似,只能key是对象而不是能是其他数据类型
说明:内存泄漏:例如dom在html页面上面,如果把dom节点从页面上面移除,其他地方也没有引用,这时候如果使用set/map进行相关存储,则该dom节点引用还是不为0,相当于内存浪费,此时使用weakset/weakmap的方式即可避免内存泄漏。

Proxy(拦截,代理)

对目标对象默认操作的拦截/改写

//new Proxy({目标对象},{拦截的方法})
let obj={name:"qiang",age:20};
//p1代理了obj.需要通过p1去操作代理的obj
let p1=new Proxy(obj,{
    //获取就会触发
    get(target,key ,proxy){
        //target:目标对象
        //key:属性名
        //proxy:当前实例
        return target[key];
    },
    set(target,prokey,value,receiver){
        //target:目标对象,此时就是obj
        //prokey:设置的属性名
        //value:设置的属性值
        //receiver:当前实例
        target[prokey]=value;
        return true;//如果设置成功return true否则false
    },
    //in 时候触发
    has(target,proKey){
        // 可以通过arguments查看传进来的参数
        if(proKey.startsWith("_")){
            return false;
        }
        return proKey in target;//如果有返回成功return true否则false
    },
});
console.log(p1.name);//qiang


function getObj(){
    return {name:"qiang"};
}
let p2=new Proxy(getObj,{
    //拦截作为函数操作时候的行为
    apply(target,object,args){
        //函数直接执行,call/apply方式执行,都会触发
        //args :表示所有参数
        //object:给函数修改this的
        if(object){
            object.fn=target;
            object.fn(...args);
            delete object.fn;
        }else{
            target(...args);
        }
    }
})
p2();

class

  • 静态方法可以被子类继承
  • 原型上的方法不可枚举
  • class没有变量提升
// let a=new A(10); class没有变量提升的,所以class定义要在前面
class A{
    //本身的属性
    constructor(x){
        //类本身
        //this :当前实例
        this.x=x;//增加的私有属性
    }
    //普通方法,相当于写在原型上
    getA(){}
    //静态方法,相当于写在原型上
    static getB(){
        console.log("静态方法");
    }
}
let a=new A(10);//如果没参数,可以省略()
for (const item in a) {
    //只输出x,验证了,class中,原型上的方法不可枚举
    console.log(item);//x
}



class B extends A{
    constructor(x){
        //super()必须写,因为子类没有this,this继承父类,
        //super()完毕之后才有this
        super(x);//就是父类的constructor
    }
    get A(){
        super.getA();//指向父类A的原型
    }
    static getBB(){
        super.getB();//super调用父类的静态的方法
    }
}
B.getBB();//静态方法,实例是获取不到该方法的

//采用class表达式让类直接执行
let a1=new class{
    constructor(name){
        console.log(name);
    }
}("信息");

Promise

    //实例一开始的状态就是pending状态,一旦new后,立马执行函数
    //执行顺序 new Promise中的代码 ===>  当前队列中的同步代码 ===> then(异步)里面的回调函数
    let pro1 = new Promise((resolve,reject)=>{
        //resolve 参数都是函数
        //reject 该参数是函数
        //当前两个函数只能执行一个,要么成功要么失败
        //如果在new Promise中有错误,那么会直接执行then中的第二个回调函数,并且把错误信息传给函数,把下方的注释代码去掉注释,可以看到控制台的效果
        // let; //使报错代码
        resolve("success");//成功Fulfilled
        reject("error");//失败Rejected
    });
    //then方法有两个回调函数
    pro1.then((res)=>{
        //resolve 成功的回调
        console.log(res);
    },(e)=>{
        //失败的回调
        console.log(e);
    });//成功打印出了success,如果我们把resolve函数注释掉,那么就会打印e
    console.log("因为then方法是异步的,所以不会等待,跳过直接进行这里的代码,所以这里先执行");

异步加载图片

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="box">

</div>
<script>
    function loadImg(url) {
        return new Promise((resolve,reject)=>{
            let img = new Image();//创建一个img实例
            img.src = url;
            img.onload = function () {//img一旦触发onload事件,就表示成功
                resolve(img);//成功的话,就拿到这个img,并且执行then方法的第一个回调函数
            };
            img.onerror = function (e) {//img一旦触发onerror事件,就表示失败
                reject(e);//失败的话,就拿到错误信息,并且执行then方法的第二个回调函数
            }
        })
    }
    loadImg("https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=4246909638,1409680877&fm=27&gp=0.jpg").then((img)=>{
        box.appendChild(img);//成功了接收这个img
    },(e)=>{
        console.log(e);//失败了就接收e
    })
</script>
</body>
</html>

catch

function loadImg(url) {
        return new Promise((resolve,reject)=>{
            let img = new Image();//创建一个img实例
            img.src = url;
            img.onload = function () {//img一旦触发onload事件,就表示成功
                resolve(img);//成功的话,就拿到这个img,并且执行then方法的第一个回调函数
            };
            img.onerror = function (e) {//img一旦触发onerror事件,就表示失败
                reject(e);//失败的话,就拿到错误信息,并且执行then方法的第二个回调函数
            }
        })
    }
    //catch方法用来捕获错误信息,在then方法中不写第二个回调函数,而是用catch来捕获错误信息
    //删掉url的部分字段,在浏览器控制台来看catch到的错误信息
    loadImg("https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/" +
        "it/u=528967148,228759238&fm=27&gp=0.jpg").then((img)=>{
            box.appendChild(img)
        //catch也可以找到then方法中的错误 去掉下面两句的注释控制台查看错误
            // let a;
            // let a;
        }).catch((e)=>{
        //捕获错误的,如果new promise中有错误会被捕获,如果then中的回调函数有错误也会被捕获
        console.log(e);
    })

all

 //console.dir(Promise) 查看Promise的方法
    //Promise.all([每一项都是Promise对象,如果不是Promise对象默认转为Promise])
    //数组中每一项都必须成功状态,才会执行Promise.all的成功的回调函数
    //默认将每一个项的参数放在数组中传回给回调函数,只要一个有错误,就会走报错的回调函数(将第一个错误参数传给回调,之后的都不会再执行)
    let p1 = new Promise((resolve, reject) => {
        resolve("OK");
    });
    let p2 = new Promise((resolve, reject) => {
        // resolve("OK");
        reject("p2Error");
    });
    let p3 = new Promise((resolve, reject) => {
        resolve("OK");
    });
    let pAll = Promise.all([p1,p2,p3]);
    console.log(pAll);//发现他也是Promise对象
    pAll.then((res)=>{
        console.log(res);//如果三个对象都是resolve成功的话,那么这里打印["OK", "OK", "OK"]
    }).catch((e)=>{
        console.log(e);//将p2改为 reject("p2Error") ,那么只打印"p2Error" 因为一旦有一个错误的,那么立马执行catch
    })

race

//只要数组中有一个对象的状态最先改变,此时当前实例的状态就跟着变
    //修改计时器延迟时间先后,查看状态改变
    //状态只跟最先改变的对象改变一次
    let p1 = new Promise((resolve, reject) => {
        setTimeout(()=>{
            resolve("OK1");
        },3000);
    });
    let p2 = new Promise((resolve, reject) => {
        setTimeout(()=>{
            resolve("OK2");
        },2200);
    });
    let p3 = new Promise((resolve, reject) => {
        setTimeout(()=>{
            resolve("OK3");
        },5000);
    });
    Promise.race([p1,p2,p3]).then((res)=>{
        console.log(res);
    }).catch((e)=>{
        console.log(e);
    })

async await

 //async函数默认返回一个promise对象
    async function getA() {
        //return出的内容就是成功回调的参数
        //如果这里出现错误,就会被catch捕获到
        // throw new Error("出错了");
        return "Cyan";
    }
    getA().then((res)=>{
        console.log(res);//打印出了"Cyan"
    }).catch((e)=>{
        console.log(e);//如果getA函数抛错,那么不会打印"Cyan",而是会打印错误
    });
    //await
    let p = new Promise((resolve, reject) =>{
        resolve("Cyan");
    });
    async function getA() {
        //await后跟Promise实例,如果不是也会默认转为Promise实例
        //直接让promise实例的回调执行 返回执行时的参数
        // console.log(await p);//"Cyan"
        //await是一个语法糖 不用通过then就可以直接拿到resolve或者reject的参数
        let a = await p;
        //等await后面的异步完成之后再去执行后面的代码
        console.log(a);
    }
    getA().then((res)=>{
        console.log(res);//这里是undefined是因为没有return
    }).catch((e)=>{
        console.log(e);
    })

上一篇: 解码方法

下一篇: elasticsearch mapping