【前端笔记】ES6-11学习记录

声明

  1. 声明变量:let 变量名
    1.变量不能重复声明
    2.块级作用域(只在代码块中有效)
    3.不存在变量提升(代码上要在调用之前声明才行)
    4.不影响作用域链
    
  2. 声明常量:const 常量名 = 常量值
    1.一定要赋初始值
    2.一般常量使用大写
    3.常量的值不能修改
    4.块级作用域(只在代码块中有效)
    5.对于数组和对象的元素修改,不算做对常量的修改,不会报错(不改变指向的地址)
    

变量解构赋值

ES6允许按照一定模式从数组和对象中提取值,对变量进行赋值

  1. 数组的解构

    const  arr= ["A","B","C","D"]
    let [a,b,c,d]=arr
    console.log(a);//打印"A"
    console.log(b);//打印"B"
    console.log(c);//打印"C"
    console.log(d);//打印"D"
    
  2. 对象的解构

    const Person = {
      name:"小A",
      age:15,
      test:function(){
        console.log("这是测试用的函数")
      }
    }
    let {name,age,test} = Person
    console.log(name);//打印"小A"
    console.log(age);//打印15
    test();//打印"这是测试用的函数"
    

    解构后方法中的this会指向全局(我用的node调试的,所以解构后getName()方法中的this指向了global,网页中估计是window),然后我把this改成了Person,不确定实战中会不会有问题,代码如下:

    const Person = {
        name:"小A",
        age:15,
        getName:function(){
         console.log("名字是"+Person.name)
        },
      }
      
      let {name,age,getName} = Person
      console.log(name);//打印"小A"
      console.log(age);//打印15
      getName();//打印"名字是小A"
    

新的声明字符串的方式

//1.声明方式
let str = `这是一个字符串`;
//2.内容中可以直接换行
let strDiv =`<div>
            <ul>
              <li>这是一个list</li>
              <li>这是一个list</li>
              <li>这是一个list</li>
              <li>这是一个list</li>
            </ul>
          </div>
          `
//3.变量拼接
let strBefore = `哈哈哈`
let strAfter = `呵呵呵`
let strAll = `${strBefore}${strAfter}`
console.log(strAll)//打印"哈哈哈呵呵呵"

简化对象写法

ES6允许直接在大括号里写入变量和函数,作为对象的属性和方法
示例:

let str = `这是一个字符串`
let fun = function(){
  console.log("这是一个函数")
}
const obj = {
  str,
  fun,
  testObj(){
    console.log("这是对象");
  }
}
console.log(obj);

箭头函数

ES6允许使用(param)=>{}定义函数

let fun = ()=>{
  console.log("这是一个函数")
}
fun()
//箭头函数:
//1.this是静态的,this始终指向函数声明时所在作用域下的this的值,无论什么方式调用(包括call,apply等),都无法改变this
//2.不能作为构造函数实例化对象
//3.不能使用arguments变量
//4.箭头函数简写
//  (1)省略小括号,当形参有且只有一个的时候
    let aPlus = a =>{return a + a ;}
//  (2)省略大括号,当代码体只有一条语句的时候,此时return必须省略,而且语句的执行结果就是函数的返回值
    let aPlus = a => a + a ;

注意:

箭头函数适合与this无关的回调,定时器,数组的方法回调
箭头函数不适合与this有关的回调,事件回调,对象的方法

函数中参数的初值

ES6允许给函数参数赋值初始值

//1. 形参初始值 具有默认值的参数,一般位置要靠后
function add(a,b,c=1){
  return a+b+c
}
let result = add(1,2)
console.log(result)
//2. 与解构赋值结合
function connect({host="127.0.0.1",username,password,port}){
  console.log(host)
  console.log(username)
  console.log(password)
  console.log(port)
}
connect({
  host:"192.168.1.101",
  username:'root',
  password:'123',
  port:3306
})

rest参数

ES6引入rest参数,用于获取函数的实参,用来代替arguments
rest参数:(需要用…开头)

function test(...args){
  console.log(args)
}
test('小A','小B','小C')//打印 [ '小A', '小B', '小C' ]

注意:rest参数必须要放到参数最后

扩展运算符

  1. 扩展运算符能将数组转换为逗号分隔的参数序列
    声明一个数组…
    const arr = ['小A','小B','小C']
    function testArr(){
      console.log(arguments);
    }
    testArr(...arr);
    //打印{ '0': '小A', '1': '小B', '2': '小C' }
    
  2. 扩展运算符能用于数组的合并
    const arrA = ['小A','小B']
    const arrB = ['小C','小D']
    const arrC = [...arrA,...arrB]
    console.log(arrC)//打印[ '小A', '小B', '小C', '小D' ]
    
  3. 扩展运算符能用于数组的克隆
    const arrA = ['小A','小B']
    const arrB = [...arrA]
    console.log(arrA)
    
  4. 将伪数组转为真正的数组
    经常见到的伪数组有函数的arguments对象、dom.querySelectorAll等获取的NodeList类(NodeList本身具有forEach方法)等。
    function test(){
        const args = [...arguments]
        console.log(args)
    }
    test('小A','小B','小C')//打印 [ '小A', '小B', '小C' ]
    

Symbol

ES6引入了一个新的原始数据类型Symbol,表示独一无二的值,是JavaScript的第七种数据类型,每个从Symbol()返回的symbol值都是唯一的。一个symbol值能作为对象属性的标识符,这是该数据类型仅有的目的

  1. Symbol特点
    (1)Symbol的值是唯一的,用来解决命名冲突的问题
    (2)Symbol值不能与其他数据进行运算
    (3)Symbol定义的对象属性不能使用for…in循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名
  2. Symbol的使用
    var a = Symbol('a')
    var b = Symbol('a')
    console.log(a === b)
    //输出false,说明symbol()是独一无二的值
    //而括号里的'a'仅仅只是用来注释
    //即使两个注释都是'a',也是不同的Symbol
    //注释只是我们自己标上去用来告诉我们自己它是哪个Symbol
    
    使用 Symbol.for() 方法和 Symbol.keyFor() 方法从全局的symbol注册表设置和取得symbol
    Symbol.for('test')//设置一个symbol并放入全局symbol注册表中,键为'test'
    Symbol.for('test')//读取全局symbol中的test
    
    console.log(Symbol.for('test')===Symbol.for("test"))//返回的是true,因为是全局的,等于号前后的都指向全局注册表中同一个symbol值,全局的symbol在其他地方也能获取
    console.log(Symbol("test2") ===Symbol("test2"))//返回的是false,因为不是全局的,两次创建的是两个不同的,独一无二的
    

迭代器

迭代器(Iterator)是一种接口,为各种不同的数据结构提供统一的访问机制,任何数据结构只要部署Iterator接口(这里的接口指的是对象中的一个属性),就可以完成遍历操作

  1. ES6创造了一种新的遍历命令for…of循环,Iterator接口主要提供for…of消费
  2. 原生具备iterator接口的数据(可用for of 遍历)
    - Array
    - Arguments
    - Set
    - Map
    - String
    - TypedArray
    - NodeList
    
  3. 工作原理
    (1)创建一个指针对象,指向当前数据结构的起始位置
    (2)第一次调用对象的next方法,指针自动指向数据结构的第一个成员
    (3)接下来不断调用next方法,指针一直往后移动,直到指向最后一个成员
    (4)每调用next方法返回一个包含value和done属性的对象
      - value表示值,done表示是否完成
    
  4. for of的使用
    const arr = ['小A','小B','小C','小D']
    for(let itemValue of arr ){
        console.log(itemValue)
    }
    let iterator = arr[Symbol.iterator]();
    console.log(iterator.next());
    console.log(iterator.next());
    console.log(iterator.next());
    console.log(iterator.next());
    console.log(iterator.next());
    
  5. 自定义遍历
    //Symbol.iterator 为每一个对象定义了默认的迭代器。该迭代器可以被 for...of 循环使用。
    const objA = {
        name:"小A",
        friends:["小B","小C","小D","小E"],
        [Symbol.iterator](){
            let index = 0;
            let _this = this;
            return {
                next:function () {
                    if(index<_this.friends.length){
                        const result = {value:_this.friends[index],done:false}
                        index++;
                        return result
                    }else{
                        return {value:undefined,done:true}
                    }
                  }
            }
        }
    }
    for(let itemValue of objA){
        console.log(itemValue)
    }
    

生成器

生成器是一个特殊的函数,能对异步编程产生影响
异步编程,纯回调函数如: node fs/ ajax/ mongodb

  1. 生成器函数的声明function * 函数名(){}
    function * aaa(){
        yield 111; //yield关键字使生成器函数执行暂停,yield关键字后面的表达式的值返回给生成器的调用者
        yield 222;
        yield 333;
    }
    let iter = aaa();
    console.log(iter.next());//打印111
    console.log(iter.next());//打印222
    console.log(iter.next());//打印333
    
  2. 生成器函数传参
    //如下代码可知:后一次调用的参数会成为前一次调用的整体返回结果
    function * test(arg){
        console.log(arg);//这里打印undefined,说明'xx'没传进来
        let a = yield 111;
        console.log(a);//这里打印'aa',说明上面一次的返回结果变成了'aa'
        console.log(yield 222)//这里打印了bb,说明了yield 222返回结果变成了bb
        yield 333;
    }
    let iter = test();
    console.log(iter.next());//打印111
    console.log(iter.next('aa'));//打印222
    console.log(iter.next('zz'));//打印333
    
    /*
    整体输出结果如下,说明调用时yield语句会执行并返回结果,但是在执行后面的调用时,前面一句yield语句的返回值就会变成后面调用时传入的参数,通过这样的方式就能实现异步编程参数传递
    { value: 111, done: false }
    aa
    { value: 222, done: false }
    zz
    { value: 333, done: false }
    */
    
异步编程

异步编程 文件操作 网络操作(ajax,request) 数据库操作
解决回调地狱的问题

  1. 案例1:
    不使用生成器时代码:
    function myPrint(){
        setTimeout(() => {
            console.log("111");
            setTimeout(() => {
                console.log("222");
                setTimeout(() => {
                    console.log("333");
                }, 1000);
            }, 1000);
        }, 1000);
    }
    myPrint()
    
    使用生成器时代码:
    function one(){
        setTimeout(()=>{
            console.log(111)
            iter.next()
        },1000)
    }
    function two(){
        setTimeout(()=>{
            console.log(222)
            iter.next()
        },1000)
    }
    function three(){
        setTimeout(()=>{
            console.log(333)
        },1000)
    }
    
    function * gen(){
        yield one();
        yield two();
        yield three();
    }
    let iter = gen();
    iter.next();
    
  2. 案例2:
    //获取用户数据 商品数据 订单数据
    function getUsers() {
        setTimeout(() => {
            let data = "用户数据"
            iterator.next(data)
        }, 1000)
      }
    function getOrders(){
        setTimeout(() => {
            let data = "订单数据"
            iterator.next(data)
        }, 1000)
    }
    function getGoods(){
        setTimeout(() => {
            let data = "商品数据"
            iterator.next(data)
        }, 1000)
    }
    function * gen(){
      let users =   yield getUsers()
      console.log(users)
      let orders =  yield getOrders()
      console.log(orders)
      let goods =    yield getGoods()
      console.log(goods)
    }
    let iterator = gen()
    iterator.next()
    

Promise

Promise是ES6引入的异步编程的新解决方案,语法上promise是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果
(1)Promise 构造函数: Promise(excutor){}
(2)Promise.prototype.then方法
(3)Promise.prototype.catch方法

//实例化Promise对象
const p = new Promise(function(resolve,reject){
  setTimeout(()=>{
   // let data = '执行成功'
   // resolve(data)
    let err = '执行失败'
    reject(data)
  },1000)
})

p.then((value)=>{
  console.log(value)
},(reason)=>{
  console.log(reason)
})
  1. Promis读取文件案例:

    const fs = require('fs')
    const p = new Promise(function(resolve,reject){
      fs.readFile('./test.txt',(err,data)=>{
        if(err) reject(err)
        resolve(data)
      })
    })
    p.then(function(value){
      console.log(value.toString())
    },function(reason){
      console.log("读取失败")
    })
    
  2. Promise封装Ajax
    原生js中的Ajax:

    //1.创建对象
    const xhr = new XMLHttpRequest();
    //2.初始化
    xhr.open("GET","https://127.0.0.1:8000")
    //3.发送
    xhr.send()
    //4.绑定事件,处理响应结果
    xhr.onreadystatechange = function(){
      if(xhr.readyState === 4){
        //判断响应状态码200-299
        if(xhr.status>=200&&xhr.status<300>){
          //成功
          console.log(xhr.response)
        }
        else{
          //失败
          console.log(xhr.status)
        }
      }
    }
    
    

    Promise封装的Ajax

    var p =new Promise(function(resolve,reject){
        //1.创建对象
        const xhr = new XMLHttpRequest();
        //2.初始化
        xhr.open("GET","https://127.0.0.1:8000")
        //3.发送
        xhr.send()
        //4.绑定事件,处理响应结果
        xhr.onreadystatechange = function(){
          if(xhr.readyState === 4){
            //判断响应状态码200-299
            if(xhr.status>=200&&xhr.status<300>){
              //成功
              resolve(xhr.response)
            }
            else{
              //失败
              reject(xhr.status)
            }
          }
        }
    })
    
    p.then(value=>{
      console.log(value)
    },reason=>{
      console.log(reason)
    })
    
  3. 链式调用
    从前往后,一个成功调用后return下一个Promise对象,可以解决回调地狱的问题

    p.then(value=>{
    
    }).then(value=>{
    
    })
    

    链式调用读取文件示例

    const fs = require('fs');
    let p = new Promise((resolve,reject)=>{
        fs.readFile('./one.txt',(err,data)=>{
            resolve(data)
        })
    })
    p.then(value=>{
        return new Promise((resolve,reject)=>{
            fs.readFile('./two.txt',(err,data)=>{
                resolve([value,data])
            })
        })
    }).then(value=>{
        return new Promise((resolve,reject)=>{
            fs.readFile('./three.txt',(err,data)=>{
                value.push(data)
                resolve(value)
            })
        })
    }).then(value=>{
        console.log(value.join('\r\n'))
    })
    
  4. Promise对象catch
    catch专门用来获取异常,通常只用then也可以

    const p = new Promise((resolve,reject)=>{
      setTimeout(()=>{
        //设置p对象的状态为失败,并设置失败的值
        reject("出错啦")
      },1000)
    })
    
    p.catch(function(reason){
      console.warn(reason)
    })
    
    

集合set

ES6提供了新的数据结构set(集合)。它类似于数组,但成员的值都是唯一的,集合实现了iterator接口,所以可以使用扩展运算符和for…of进行遍历

  1. 集合的属性和方法
    size 返回集合的元素个数
    add 增加一个新元素,返回当前集合
    delete 删除元素,返回boolean值
    has 检测集合中是否包含某个元素,返回boolean值
    
  2. 声明集合和使用
    let s = new Set()
    let s2 = new Set(["小A","小B","小C","小A","小D"])
    console.log(s2.size)//打印4 因为小A重复,在集合大小里面不计算重复的内容
    s2.add('小E')
    s2.delete('小A')
    console.log(s2.has('小A'))
    console.log(s2)//Set(4) { '小B', '小C', '小D', '小E' }
    s2.clear()
    
  3. 集合案例
    let arr = [1,2,3,4,5,4,3,2,1]
    //1.数组去重
    let result = [...new Set(arr)]
    //2.数组求交集
    let arr2 = [4,5,6,5,6]
    let result2 = [...new Set(arr)].filter(item=>{
      let s2 = new Set(arr2)
      if(s2.has(item)){
        return true
      }
      else {
        return false
        }
    })
    //求交集的另一种写法
    let result2 = [...new Set(arr)].filter(item=>new Set(arr2).has(item))
    console.log(result2)//打印 [ 4, 5 ]
    //3.数组求并集
    let union = [...new Set([...arr,...arr2])]
    console.log(union)
    //4.数组求差集
    //arr1和arr2的差集,就是arr1中有,arr2没有
    //arr2和arr1的差集,就是arr2中有,arr1没有
    let diff = [...new Set(arr)].filter(item=>!(new Set(arr2).has(item)))
    console.log(diff)
    

Map

ES6中提供了Map数据结构,它类似于对象,也是键值对的集合。但是键的范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map也实现了iterator接口,所以可以使用扩展运算符和for of进行遍历。

  1. Map的属性和方法
    size 返回Map的元素个数
    set 增加一个新元素,返回当前Map
    get 返回键名对象的键值
    has 检测Map中是否包含某个元素,返回boolean值
    clear 清空集合,返回undefined
    
  2. 声明Map和使用Map
    //声明Map
    let m = new Map()
    m.set('name','小A')
    m.set('change',function(){
      console.log("小A改变了")
    })
    console.log(m)
    /*
    结果:
    Map(2) { 'name' => '小A', 'change' => [Function (anonymous)] }
    */
    
    //另一种方式添加键值
    let mykey = {
      person:'小A'
    }
    m.set(mykey,['小B','小C'])
    console.log(m)
    
    /*
    结果:
    Map(3) {
      'name' => '小A',
      'change' => [Function (anonymous)],
      { person: '小A' } => [ '小B', '小C' ]
    }
    */
    //其他方法
    console.log(m.size)
    m.delete('name')
    console.log(m.get('change'))
    for(let v of m){
      console.log(v)
    }
    m.clear()
    
    

class 类

ES6 提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板,通过class关键字,可以定义类。基本上,ES6的class可以看作是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更清晰、更像面向对象编程的语法而已
知识点

class 声明类
constructor 定义构造函数初始化
extends 继承父类
super 调用父级构造方法
static 定义静态方法和属性
父类方法可以重写
  1. 类的写法

    class 类名{
      //构造方法,名字不能修改
      constructor(参数1,参数2){
        this.属性1 = 参数1
        this.属性2 = 参数2
      }
      //方法,必须使用该语法 即方法名(){}
      //不能使用es5的对象完整形式 方法名:function(){}
      方法名(){}
    }
    //实例化
    let 对象 = new 类名(参数1,参数2)
    
  2. class静态成员
    通过static关键字声明的属性,属于类,而不属于实例化对象,需要通过 类名.静态属性 来获取

  3. 构造函数继承
    ES5构造函数的继承

    //父类
    function Phone(brand,price){
      this.brand = brand
      this.price = price
    }
    Phone.prototype.call = function(){
      console.log("我可以打电话")
    }
    //子类
    function SmartPhone(brand,price,color,size){
      Phone.call(this,brand,price)
      this.color = color
      this.size = size
    }
    //设置子级构造函数的原型
    SmartPhone.prototype = new Phone
    SmartPhone.prototype.constructor = SmartPhone
    
    //声明子类的方法
    SmartPhone.prototype.photo = function(){
      console.log("我可以拍照")
    }
    SmartPhone.prototype.playGame = function(){
      console.log("我可以玩游戏")
    }
    
    

    ES6类的继承

    class Phone{
      constructor(brand,price){
        this.brand = brand;
        this.price = price;
      }
      call(){
        console.log("我可以打电话")
      }
    }
    
    class SmartPhone extends Phone{
      constructor(brand,price,color,size){
        super(brand,price)//相当于Phone.call(this,brand,price)
        this.color = color
        this.size = size
      }
      photo(){
        console.log("拍照")
      }
      playGame(){
        console.log("玩游戏")
      }
    }
    
  4. 子类对父类方法的重写
    不能通过子类的成员中调用super来调用父类的方法
    只能在子类中完全重写父类的方法

  5. class中的getter和setter设置

    class Phone{
      get price(){
        console.log("价格属性被读取了")
      }
      set price(newVal){
        console.log("价格属性被修改了")
      }
    }
    let s = new Phone()
    s.price = 'free'
    

ES6的数据拓展

// Number.EPSILON是JavaScript表示的最小精度
// EPSILON属性的值接近于2.2204460492503130808472633361816E-16
理论上可以用来比较大小
function equal(a,b){
  if(Math.abs(a-b)<Number.EPSILON){
    return true
  }else{
    return false
  }
}
//1.二进制和八进制
let b = 0b1010 //二进制0b开头表示
let o = 0o777 //八进制0o开头表示
let d = 100 //十进制直接写
let x = 0xff //十六进制用0x表示
//2.Number.isFinite检测一个数值是否为有限数

//3.Number.isNaN 检测一个数值是否为NaN

//4.Number.parseInt Number.parseFloat字符串转整数

//5.Number.isInteger判断一个数是否为整数

//6.Math.trunc将数字的小数部分抹掉

//7.Math.sign 判断一个数到底为正数(返回1) 负数(返回-1) 还是0(返回0)

对象方法拓展

//1.Object.is判断两个对象是否完全相等
  console.log(Object.is(120,120))//true
  console.log(Object.is(NaN,NaN))//true
  console.log(NaN===NaN)//false
//2.Object.assign 对象的合并
  Object.assign(obj1,obj2)
  //如果属性出现重名,合并后面参数会把前面参数覆盖
  //如果属性原本其中一个没有,那么合并后会加上
//3.Object.setPrototypeOf 设置原型对象 Object.getPrototypeOf获取原型对象

ES6的模块化

模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来

  1. 模块化的好处

    - 防止命名冲突
    - 代码复用
    - 高维护性
    
  2. ES6之前的模块化规范产品

    规范=>规范对应的产品
    CommonJS =>NodeJS、Browserify
    AMD=>requireJS
    CMD=>seaJS
    
  3. ES6模块化语法
    模块功能主要由两个命令构成:export和import
    export命令用于规定模块的对外接口
    import命令用于输入其他模块提供的功能

  4. 简单试用

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <script type="module">
            import * as test from "./src/js/test.js"
            console.log(test)
        </script>
    </body>
    </html>
    

    js代码:

    export let name = "小A"
    export function getName(){
        console.log("小A")
    }
    
  5. 暴露方式
    分别暴露

    export let name = "小A"
    export function getName(){
        console.log("小A")
    }
    

    统一暴露

    let name = "小A"
    function getName(){
      console.log("小A")
    }
    export {name,getName}
    

    默认暴露

    export default{
      name:"小A",
      getName(){
         console.log("小A")
      }
    }
    
  6. 引用方式
    通用方式导入

    import * as test from "./src/js/test.js"
    

    解构赋值形式

    import {name,getName} from "./src/js/test.js"
    import {name as personName ,getName} from"./src/js/test.js"//使用别名
    import {default as test}from "./src/js/test.js"
    

    简便形式(只能针对默认暴露使用)

    import test form "./src/js/test.js"
    
  7. 使用ES6模块化的另一种方式
    通过一个入口文件(通常是app.js)统一引入
    然后html页面里面只写

    <script src = "./src/js/app.js" type = module></script>
    
  8. ES6模块化代码在项目中的使用方式
    通过babel进行转化,将ES6转化为ES5

    1.安装工具 babel-cli babel-preset-env browserify(或者webpack)
    npm i babel-cli babel-preset-env browserify -D
    //-D代表开发依赖,即dev环境
    2.转化(等号中间不要加空格)
    npx babel src/js -d dist/js --presets=babel-preset-env 
    3.打包
    npx browserify dist/js/app.js -o dist/bundle.js
    

    打包完了以后html里script的src要进行修改才能使用

ES7新特性

  1. 数组.includes(元素)用于判断数组中是否含有某元素,返回boolean
  2. ** 幂运算 2的10次方可以写成2**10Math.pow(2,10)一样

ES8新特性

async和await

async和await两种语法结合可以让异步代码像同步代码一样

  1. async函数
    async函数的返回值为promise对象
    promise对象的结果由async函数执行的返回值决定
    async function fn(){
      //返回一个字符串
      //return '哈哈哈'
      //抛出错误,返回的结果是一个失败的promise对象
      throw new Error("出错啦")
    }
    const result = fn()
    console.log(result)
    
    注意:
    1.如果代码中返回的结果不是一个promise类型的对象,运行时返回的结果也是一个成功的promise对象
    2.如果代码中抛出错误,返回的结果是一个失败的Promise
    3.如果代码中返回值设置的是Promise对象,返回结果就会跟我们自己返回的Promise一致
    
  2. await表达式
    await必须要放在async函数中
    await右侧的表达式一般为promise对象
    await返回的是promise成功的值
    await的promise失败了,就会抛出异常,需要通过try…catch捕获处理
    示例:
    const p = new Promise((resolve,reject)=>{
      //resolve("用户数据")
      reject("失败啦")
    })
    //await要放在async函数中
    async function main(){
      try{
        let result = await p//await返回的结果是promise对象成功的值
        console.log(result)
      }
      catch(e){
        console.log(e)//在catch里面可以得到失败的值
      }
    }
    
  3. async await读取文件实践
    const fs = require('fs')
    function readOneTxt(){
        return new Promise((resolve,reject)=>{
            fs.readFile('./one.txt',(err,data)=>{
                if (err) reject(err)
                resolve(data) 
            })
        })
    }
    function readTwoTxt(){
        return new Promise((resolve,reject)=>{
            fs.readFile('./two.txt',(err,data)=>{
                if (err) reject(err)
                resolve(data) 
            })
        })
    }
    
    function readThreeTxt(){
        return new Promise((resolve,reject)=>{
            fs.readFile('./three.txt',(err,data)=>{
                if (err) reject(err)
                resolve(data) 
            })
        })
    }
    
    async function main(){
        let oneTxt = await readOneTxt()
        let twoTxt = await readTwoTxt()
        let threeTxt = await readThreeTxt()
        console.log(oneTxt.toString())
        console.log(twoTxt.toString())
        console.log(threeTxt.toString())
    }
    main()
    

ES8对象方法拓展

获取对象所有的键Object.keys(对象)
获取对象所有的值Object.values(对象)
对象转二维数组(键值数组) Object.entries(对象)

键值数组: [[键1,值1],[键2,值2]...]
//方便创建map
const m = new Map(Object.entries(对象))

获取对象属性的描述对象Object.getOwnPropertyDescriptors(对象)

ES9 rest参数与spread扩展运算符

在ES6中已经引入了rest参数与spread扩展运算符,但是ES6只针对于数组,ES9中为对象提供了像数组一样的rest参数和扩展运算符
可以做对象的合并

ES9正则扩展

  1. 命名捕获分组
    之前的写法:
    let str = '<a href = "http://127.0.0.1/">本地服务器</a>'
    const reg = /<a href = "(.*)">(.*)<\/a>/
    const result = reg.exe(str)
    console.log(result[1])//打印'http://127.0.0.1/'
    console.log(result[1])//打印'本地服务器'
    
    现在的写法:
    let str = '<a href = "http://127.0.0.1/">本地服务器</a>'
    const reg = /<a href = "(?<url>.*)">(?<text>.*)<\/a>/
    console.log(result.groups.url)
    console.log(result.groups.text)
    //好处是即使正则表达式结构变了也只要改表达式里的名字就行
    
  2. 反向断言
    //声明字符串
    let str = 'JS5211314你知道么555啦啦啦'
    //正向断言
    //const reg = /\d+(?=啦)/
    //const result = reg.exec(str)
    //反向断言
    const reg = /(?<=么)/
    const result = reg.exec(str)
    console.log(result)
    
  3. dotAll模式
    //dot . 元字符 除换行字符以外的任意单个字符
    //加匹配模式s以后.可以匹配任意字符
    let str =  `
    <ul>
        <li>
            <a>肖申克的救赎</a>
            <p>上映日期: 1994-09-10</p>
        </li>
        <li>
        <a>阿甘正传</a>
        <p>上映日期: 1994-07-06</p>
        </li>
    </ul>
    `
    const reg = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/gs
    
    let result
    let data = []
    while(result = reg.exec(str)){
        data.push({title:result[1],time:result[2]})
    }
    console.log(data)
    

ES10

  1. 二维数组转对象Object.fromEntries(二维数组)
  2. 字符串扩展方法
    字符串.trimStart()清除字符串左侧空白
    字符串.trimEnd()清除字符串右侧空白
  3. flat与flatMap
    flat将多维数组转低维数组
    const arr = [1,2,3,4,[5,6,[7,8,9]]]//这是一个三维数组
    console.log(arr.flat())//转为二维数组
    console.log(arr.flat(2))//转为一维数组
    //参数是深度,是一个数字,默认是1
    
    flatMap是Map和flat操作的结合,可以直接将结果变为一维数组
    const arr = [1,2,3,4]
    const result = arr.flatMap(item = >{item*10})
    console.log(result)
    
  4. Symbol的扩展
    Symbol.prototype.description获取字符串属性的描述

ES11

  1. 私有属性
    属性前用#标记为私有

    class Person{
      //公有属性
      name
      //私有属性
      #age
      #weight
      constructor(name,age,weight){
        this.name = name
        this.#age = age
        this.#weight = weight
      }
      intro(){
        console.log(this.name)
        console.log(this.#age)
        console.log(this.#weight)
      }
    }
    const girl = new Person('小红',18,'45kg')
    //console.log(girl.#age)无法获取
    girl.intro();//可以获取
    
  2. Promise.allSettled(promise对象数组)方法
    可以返回一个成功的Promise对象,对象的值是参数中每一个promise对象的判断结果和值
    Promise.all()很像,但是Promise.all()的参数数组只有全部成功才会返回成功的promise
    他们两个通常都用来做批量异步任务

  3. 字符串扩展matchAll方法
    用于批量提取数据(爬虫)

    let str =  `
    <ul>
        <li>
            <a>肖申克的救赎</a>
            <p>上映日期: 1994-09-10</p>
        </li>
        <li>
        <a>阿甘正传</a>
        <p>上映日期: 1994-07-06</p>
        </li>
    </ul>
    `
    //声明正则
    const reg = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/sg
    const result = str.matchAll(reg)
    //for(let v of result){
    //  console.log(v)
    //}
    const arr = [...result]
    console.log(arr)
    
  4. 可选链操作符?.
    以前的写法

    function main(config){
      const dbHost = config&&config.db&&config.db.host//避免用户不传参数报错
      console.log(dbHost)
    }
    main({
      db:{
        host:'192.168.1.101',
        username:'root'
      },
      cache:{
         host:'192.168.1.102',
        username:'admin'
      }
    
    })
    

    现在的写法

    function main(config){
      const dbHost = config?.db?.host//免去层层判断
      console.log(dbHost)
    }
    main()
    
  5. 动态import
    实现了按需加载,使用的是import函数,这个函数参数是路径,返回结果是一个promise对象,这个对象成功的值是我们需要引入的模块暴露的对象。这样提高了加载的效率

    const btn = document.getElementById('btn')
    btn.onclick = function(){
      import('./test.js').then(module=>{
        module.myTest()//myTest是'./test.js'中暴露的函数
      })
    }
    
  6. BigInt类型 大整型
    主要用于大数值的运算注:不能跟普通整数运算
    声明:let n = 521n(在普通的整数后面加一个n)
    普通整型转换为大整型:BigInt(整数)

    //大数值运算
    let max = Number.MAX_SAFE_INTEGER
    console.log(max)
    console.log(max+1)
    console.log(max+2)
    console.log(BigInt(max))
    console.log(BigInt(max)+BigInt(1))
    console.log(BigInt(max)+BigInt(2))
    /*
    输出:
    9007199254740991
    9007199254740992
    9007199254740992
    9007199254740991n
    9007199254740992n
    9007199254740993n
    */
    
  7. 绝对全局对象this globalThis
    这个对象始终指向全局对象
    网页中指向window
    nodeJS中指向global

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

棋小仙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值