Es6新增的知识

318 阅读23分钟

let和const

  • let声明变量,该变量只在let所在的代码块中有效。
  • let只能声明一次。不能重复声明
  • let没有变量提升,let声明的变量不能在声明前使用

暂时性死区:let声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”

  • const声明只读变量,const声明后该变量不能被修改
  • const声明也存在暂时性死区
  • const声明的值如果是基本数据类型那等于常量,如果声明复杂数据类型那么指针指向不变

解构赋值

解构赋值提供了快速批量为变量赋值的方法,解决了从嵌套对象中获取数据的问题

//let [a, b, c] = [1, 2, 3];//a=1b=2,c=3
let obj = {p: ['hello', {y: 'world'}] };
      let {p:[a,{y:b}]}=obj;
      console.log(a+' '+b)//hello world
  • 解构赋值的核心是一一对应
  • 解构赋值是可忽略的,但是需要将位置空出来

模板字符串

在两个反引号表示内容是模板字符串,模板字符串中能够加入变量和表达式

  function a(a,b){
      console.log(`你好${a},欢迎来到${b},现在时间是${new Date().toLocaleString()}`)
  }
  a('Tom','China')//你好Tom,欢迎来到China,现在时间是2020/8/21 下午4:01:56
  • 模板字符串中的所有空格和换行都会被保留

对象字面量

ES6允许对象的属性直接写变量,这时候属性名是变量名,属性值是变量值。

const age = 12;
const name = "Amy";
const person = {age, name};
person   //{age: 12, name: "Amy"}

扩展运算符

拓展运算符(...)用于取出参数对象所有可遍历属性然后拷贝到当前对象。

let a=[1,2,3,4]
let b=[5,6,7,8]
let c=[...a,...b,9]
console.log(c)//[1, 2, 3, 4, 5, 6, 7, 8, 9]

函数的call方法与apply方法的区别就是call是逐个传参,apply是数组传参,有了扩展运算符之后基本就只用call不用apply了。

基本数据类型Symbol

表示独一无二,用来定义对象的唯一属性名。

let sy = Symbol("KK");
console.log(sy);   // Symbol(KK)
typeof(sy);        // "symbol"

// 相同参数 Symbol() 返回的值不相等
let sy1 = Symbol("kk"); 
sy === sy1;       // false

箭头函数

基本语法:参数=>函数体

  • 箭头函数是自带return的,加上大括号就没有return了

    let a=()=>5; a()//5 let b=()=>{5} b()//underfined

  • 箭头函数没有自己的this,箭头函数的this用的就是执行上下文中的this

迭代方法for...of循环

  • 不能迭代Object对象,能够迭代Array,String,Map,Set

    const nums = ["zero", "one", "two"];
        for (let num of nums) {
          console.log(num);
        }
    const str = "zero";
        for (let item of str) {
          console.log(item);
        }
    

Class语法糖

class (类)作为对象的模板被引入,可以通过 class 关键字定义类,本质是function,让对象原型的写法更加清晰、更像面向对象编程的语法。

       class a{
           constructor(name){
             //在这里添加属性
             this.name=name
           }
          //在这里添加方法,添加的方法会放在原型中
          use(){
              console.log('方法')
          }
       }
       let b=new a('参数')
       console.log(b)

模块化编程

ES6 引入了模块化,其设计思想是在编译时就能确定模块的依赖关系,以及输入和输出的变量。ES6 的模块化分为导出(export) @与导入(import)两个模块。

当我们想要使用外部js文件的方法或者变量时,我们往往需要将外部的js文件整个引入文档中来,如果有很多个这样的js文件,都导入一个文档可能就会出现重复定义的变量而抛出错误。

模块化是让我们不用将js文件整个导入文档中,我们需要使用哪一个变量或者函数那就在外部的js文件中将他导出,export {要使用的变量}。然后在文档中import{变量名}来导入使用。

通过模块,js文件之间也可以进行相互依赖,让程序开发变得更有层次,有规划

  • 模块会自动开启严格模式,不管你有没有在模块头部加上use strict

  • 模块中可以导入和导出各种类型的变量,如函数,对象,字符串,数字,布尔值,类等。

  • 每个模块都有自己的上下文,模块内声明的变量都是局部变量,不会污染全局作用域。

  • 每一个模块只加载一次(是单例的), 若再去加载同目录下同文件,直接从内存中读取。

Set对象

set对象是一个由各种类型数据组成的集合,类数组,set对象里的数据不能重复(全等)

方法:

  • add,在set对象的末尾添加元素,返回set对象
  • clear,移出set对象内所有元素
  • has,判断是否包含
  • delete,移出set对象中值与参数相等的元素

属性:size查询长度

Set的转换

// ArraySet
var mySet = new Set(["value1", "value2", "value3"]);
// 用...操作符,将 SetArray
var myArray = [...mySet];

// String 转 Set
var mySet = new Set('hello');  // Set(4) {"h", "e", "l", "o"}
// 注:Set 中 toString 方法是不能将 Set 转换成 String

使用Set对象对数组去重

var mySet = new Set([1, 2, 3, 4, 4]);
[...mySet]; // [1, 2, 3, 4]

Map对象

Map 对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。

Map对象和Object对象的区别

  • 一个 Object 的键只能是字符串或者 Symbols,但一个 Map 的键可以是任意值。
  • Map 中的键值是有序的(FIFO 原则),而添加到对象中的键则不是。
  • Map 的键值对个数可以从 size 属性获取,而 Object 的键值对个数只能手动计算。
  • Object 都有自己的原型,原型链上的键名有可能和你自己在对象上的设置的键名产生冲突。

方法:

  • get,查询键,返回值
  • set,添加键值对
  • has,查询是否有指定元素
  • clear,移除所有键值对
  • delete,移除指定键值对

属性:size查询长度

Proxy代理对象

Proxy 可以对目标对象的读取、函数调用等操作进行拦截,然后进行操作处理。它不直接操作对象,而是像代理模式,通过对象的代理对象进行操作,在进行这些操作时,可以添加一些需要的额外操作。

  • 新建一个代理对象,target表示代理的目标对象,handler是一个对象,声明代理对象的行为

    let proxy = new Proxy(target, handler)

  • 代理对象拦截的行为有13种(复制的):跳转地址

1. get(target, propKey, receiver):拦截对象属性的读取,比如proxy.fooproxy['foo']。 2. set(target, propKey, value, receiver):拦截对象属性的设置,比如proxy.foo = vproxy['foo'] = v,返回一个布尔值。 3. has(target, propKey):拦截propKey in proxy的操作,返回一个布尔值。 4. deleteProperty(target, propKey):拦截delete proxy[propKey]的操作,返回一个布尔值。 5. ownKeys(target):拦截Object.getOwnPropertyNames(proxy)Object.getOwnPropertySymbols(proxy)Object.keys(proxy)for...in循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()的返回结果仅包括目标对象自身的可遍历属性。 6. getOwnPropertyDescriptor(target, propKey):拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。 7. defineProperty(target, propKey, propDesc):拦截Object.defineProperty(proxy, propKey, propDesc)Object.defineProperties(proxy, propDescs),返回一个布尔值。 8. preventExtensions(target):拦截Object.preventExtensions(proxy),返回一个布尔值。 9. getPrototypeOf(target):拦截Object.getPrototypeOf(proxy),返回一个对象。 10. isExtensible(target):拦截Object.isExtensible(proxy),返回一个布尔值。 11. setPrototypeOf(target, proto):拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。 12. apply(target, object, args):拦截 Proxy 实例作为函数调用的操作,比如proxy(...args)proxy.call(object, ...args)proxy.apply(...)。 13. construct(target, args):拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(...args)

  • 以拦截get为例:

     let obj={name:'lsq',age:23}
       let proxy=new Proxy(obj,{
           get:function(target,key){
               console.log('自定义操作')
               return target[key]
           }
       })
       console.log(proxy.name)//自定义操作 lsq
       console.log(proxy.age)//自定义操作 23
    
  • 这让我想到了对象的访问器属性:

      var obj={_name:'lsq',age:23}
      Object.defineProperty(obj,'name',{
          get:function(){
              console.log('get的自定义操作')
              return obj._name
          },
          set:function(val){
              console.log('set的自定义操作')
              this._name=val;
          }
      })
    console.log(obj.name)
    obj.name='qd'
    
  • 他们的区别应该是访问器属性是修改了原对象该属性get,set方法,而代理方法原对象默认行为并没有被修改,只是在给这个行为包了一层行为。

Reflect对象

ES6 中将 Object 的一些明显属于语言内部的方法移植到了 Reflect 对象上(当前某些方法会同时存在于 Object 和 Reflect 对象上),未来的新方法会只部署在 Reflect 对象上。

Reflect 对象对某些方法的返回结果进行了修改,使其更合理。

Reflect 对象使用函数的方式实现了 Object 的命令式操作。

  • 仔细一看就发现,Reflect对象其实是将原对象上的属于语言内部的方法移植出来形成的对象。移植的方法就是代理对象Proxy拦截的13种行为

  • Reflect对象移植出的行为就是行为本身,无法添加自定义的行为

    let exam = {
        name: "Tom",
        age: 24,
    }
    Reflect.get(exam, 'name'); // "Tom"
    exam.name;//"Tom"
    

所以说这到底是干啥了?或许正如上面说的,实现了这两点内容,深层次含义我还不理解

  • Reflect 对象对某些方法的返回结果进行了修改,使其更合理。
  • Reflect 对象使用函数的方式实现了 Object 的命令式操作。

Promise对象(查看详细点击

Promise 是一个对象是异步编程的一种解决方案。

  • Promise创建微任务队列,用于异步的优点就是他有执行顺序

  • Promise 异步操作有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。

    const p1 = new Promise(function(resolve,reject){
        resolve('success1');
        resolve('success2');//无效
    }); 
    
  • 状态只能在Promise的回调函数里改变,状态改变之后就不能再改变了

  • Promise回调函数接收两个参数,一个成功状态一个失败状态

  • Promise是立即执行的,只要新建就执行

方法:

  • then,接收两个函数参数,第一个是成功状态的回调,第二个是失败状态的回调

    const p1 = new Promise(function(resolve,reject){
        reject();
        resolve();//无效}).then(
        ()=>console.log('成功回调'),
        ()=>console.log('失败的回调')//打印出)
    
  • then方法会return一个promise对象,默认的返回是Promise.resolve(),可以用主动设置返回Promise.reject()来改变默认的状态

    const p1 = new Promise(function(resolve,reject){
        reject();
        resolve();//无效
    }).then(
        ()=>console.log('成功回调'),
        ()=>{
    console.log('失败的回调');//打印出
    return Promise.reject()
    }).then(
    ()=>console.log('第二层的成功'),
    ()=>console.log('第二层的失败'))//打印出
    
  • catch,默认的失败执行函数,每一个then都有两个回调函数显得很麻烦,catch方法在链式操作的最后加上,给每个then方法默认的失败回调,此时then方法就变得简单了

    const p1 = new Promise(function(resolve,reject){
        reject();
    }).then(
     ()=>console.log('成功回调'))
    .catch(()=>console.log('默认的失败回调'))//打印出
    
  • .finally,不管成果或者失败都会执行的操作,相当于then的两个回调函数是一个函数

  • Promise.all,方法接收多个Promise对象作为参数(要以数组形式),作用是统一处理Promise。多个Promise对象的状态都是成功的那么该方法返回一个成功状态,如果有一个失败那么该方法返回一个失败状态

    const a = new Promise((res,rej)=>res('a'));
    const b = new Promise((res,rej)=>res('b'));
    const c = Promise.all([a, b])
      .then((a)=>console.log(a))
      .catch(()=>console.log('失败'));
    

  • Promise.allSettled,与all的区别就是allSettled不管传入的Promise是成功状态还是失败状态都会执行下去,就像是finally与then的区别。

    const a = new Promise((res,rej)=>res('a'));
    const b = new Promise((res,rej)=>rej('b'));
    const c = Promise.allSettled([a, b])
      .then((a)=>console.log(a))
    

  • Promise.race,传递参数与all相同,但是race只处理一个返回状态最快的Promise对象,就是谁返回的状态快用谁的状态

    const a = new Promise((res,rej)=>setTimeout(()=>res('成功了'),0));
    const b = new Promise((res,rej)=>setTimeout(()=>rej('失败了'),0));
    const c = Promise.race([a, b])
      .then((a)=>console.log(a))
      .catch((a)=>console.log(a))
    

Generator函数(查看详细点击

通过 yield 关键字,把函数的执行流挂起,为改变执行流程提供了可能,从而为异步编程提供解决方案。

function* func(){
 console.log("one");
 yield '1';
 console.log("two");
 yield '2';
  console.log("three");
 return '3';
}
let f=func()
console.log(f.next())
 f.next()
f.next()
  • 在我看来,Generator函数就是通过yield关键字分成几个单独的部分,通过遍历器来一步步的运行这几个部分的代码

async函数

async 是 ES7 才有的与异步操作有关的关键字,和 Promise , Generator 有很大关联的。

  • 在定义函数的前添加async关键字的函数就是async函数,async函数默认返回一个promise对象,函数体内部的返回值作为promise对象状态的参数传递

    async function a(){
            return 'a'
    }
    console.log(a())
    

await表达式

  • await表达式是只存在于async函数中的,阻断程序的执行,等待await表达式后的函数体执行完毕再执行之后的代码

  • await 操作符用于等待一个 Promise 对象(大多数情况下是如此,当然等待的代码可以是任何操作,不过如果是正常的同步代码那好像没有使用await的必要了), 它只能在异步函数 async function 内部使用。

  • 返回 Promise 对象的处理结果。如果等待的不是 Promise 对象,则返回该值本身。

    let a=new Promise(function(res,rej){
            res()
    }).then(function(){
        console.log('a')
    })
    async function b(){
        await a//如果没有这一行那么结果应该打印b a
        console.log('b')
    }
    b()//a b
    
  • async/await就是promise对象的语法糖,实质上就是promise操作