关于ES6

Posted Tap? taq

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于ES6相关的知识,希望对你有一定的参考价值。

ES6环境:webpack3.0

ES6 声明变量

let:相当于ES5的var
     但var没有块级作用域,而let有
     没有预解析,不存在变量提升
     在代码块内,let要先定义完再使用,只要let定义变量在之前使用都是报错(为暂时性死区(TDZ))
     同一个作用域里不能重复定义变量
     for循环中,for循环里面是父级作用域,循环里面又是一个
     推荐以后使用let

const:定义常量(定义完变量后不能再次被赋值)
       但对于一些对象上自身的方法,可以利用其方法进行更改(如array.push,...)
       有一特例:Object.freeze(能阻止改变,即使是对象自身上的方法也不能被改变)
       

ES6 解构赋值(实用)

用在数据交互ajax时非常有用

注意:左右两边,结构格式要保持一致
e.g. let [a,b,c]=[1,2,3] => a=1,b=2,c=3
     let json={
        name:\'ckx\',
        age:20,
        job:\'wu\'
     }
     let {name,age,job}=json => name=\'ckx\',age=20,job=\'wu\'
     
解构时可以给默认值:let [a,b,c=\'暂无\']=[1,2]

解构可用于交换值:
let a=1;
let b=2;
[a,b]=[b,a];

解构可用于接收函数返回的多个值:
function a(){
    return{
        b:1,
        c:2
    }
}
let {b,c}=a() => b=1,c=2
     

ES6 字符串

字符串模板:`xxxxxxx`
优点:可随意换行
      `xxx${变量名}xxx`
e.g. let a=1;
     let b=2;
     let str=`这里有${a}个人
              那里有${b}个人`
              
字符串新增的一些方法:
str.includes(\'xxx\'):xxx是否包含在str中(返回true/false)
str.indexOf(\'xxx\'):返回xxx在str中的索引位置,找不到则返回-1
str.startsWith(\'xxx\'):str是否以xxx开头(返回true/false)  
str.endsWith(\'xxx\'):str是否以xxx结尾(返回true/false)
str.repeat(n):str重复n次
str.padStart(整个字符串长度(填充后的长度),填充的东西):str往前填充
str.padEnd(整个字符串长度(填充后的长度),填充的东西):str往后填充

ES6 函数

 设置默认参数:function({a=\'xx\',b=\'xx\'}){} 或 function(a,b){a=a || \'xx\'; b=b || \'xx\'}或function({a,b}={}){}
 函数参数默认已经定义了,不能再使用let,const声明
 
 扩展运算符/剩余运算符:...
 展开数组:let arr=[\'a\',\'b\',\'c\'];
          ...arr => \'a\',\'b\',\'c\'
 合为数组:function(...a){...}
          show(1,2,3);
          此时的a为[\'1\',\'2\',\'3\']
 当作剩余参数:function(a,b,...c){
                   console.log(a);
                   console.log(b);
                   console.log(c);
               }
              show(1,2,3,4,5);
              此时输出的a为1,b为2,c为3,4,5
              
 箭头函数:()=> return的东西
          ()=>{...}
 箭头函数的this指向定义函数所在的对象,而不是运行时所在的对象
 箭头函数没有arguments,用\'...\'
 箭头函数不能当构造函数
 

ES6 数组

ES5里循环的方法:
for
while
arr.forEach(fn(val,index,arr){}) / arr.forEach(fn,this指向的对象)
arr.map(fn(val,index,arr){}) / arr.map(fn,this指向的对象) (会返回一个新数组 )
arr.filter(fn(val,index,arr){}):过滤一些不合格的元素
arr.some(fn(val,index,arr){}):类似查找,数组里面某一个元素符合条件,返回true
arr.every(fn(val,index,arr){}):数组里面所有元素符合条件,返回true
arr.reduce(fn(prev,current,index,arr)):可用于求和/阶乘...(prev+current,类似递归)(方向是从左往右)
arr.reduceRight():类似arr.reduce,方向是从右往左
for(xx of xxx):xx在xxx里面的循环(可配合arr.keys()(数组下标),arr.entries()(数组的某一项)使用)

数组的一些新增方法:
扩展运算符/剩余运算符:... (上面有介绍)
Array.from(xxx):把类数组对象(xxx)转成数组
Array.of(\'xx\',\'xxx\',\'xx\'):把一组值合并转为一个数组
arr.find(fn(val,index,arr){}):在arr中找到第一个符合此条件的元素,若找不到则返回undefined
arr.findIndex(fn(val,index,arr){}):在arr中找到符合元素的下标位置,没找到则返回-1
arr.fill(\'xxx\',x,y):xxx填充数组(范围是从x到y)
arr.includes(\'xxx\'):判断arr是否包含xxx

ES6 对象

对象中的函数可以简写:let json={
                           a,
                           show(){...}  (建议不要使用箭头函数)
                     }
 
Object.is():用来比较两个值是否相等(肉眼看的相等就相等)

新对象=Object.assign(目标对象,source1,source2,...):用来合并对象(用途:复制一个对象/数组,合并参数)

Object.keys(xxx):遍历对象的键值

Object.entries():遍历对象的每一项

Object.values():遍历对象的值

...:对象解构:let json={a:3,b:4};
              let json2={...json};  => json2={a:3,b:4}
              

ES6 Promise

作用:解决异步回调问题

let promise=new Promise(function(resolve,reject){  //resolve为成功调用,reject为失败调用
            resolve(\'成功\');
            reject(\'失败\');
})
promise.then(success的fn,fail的fn)
=> promise.then(res=>{
        ... //会输出resolve的内容
   },err=>{
        ... //会输出reject的内容
   })
promise.catch(err=>{...})  //捕获错误  

连贯用法:new Promise(fn).then(res=>{}).catch(err=>{})

Promise.all([promise1,promise2,...]):把promise打包,扔到一个数组里,打包完还是promise对象。必须确保所有promise对象都是resolve状态才可返回(可利用此来调整输出的顺序,相当于把异步变为同步,但还是异步的)

Promise.race([p1,p2,...]):与Promise.all类似,但只要其中有一个promise对象是resolve状态即可返回

ES6 模块化

定义(导出)模块:export \'xxx\'
引入模块的几种方法:import \'xxx\'
                   import {xx,xx} from \'xxxx\'
                   import {xxx as xx} from \'xxxx\'
                   import * from \'xxxx\'
                   
import:
可以是相对路径,也可以是绝对路径
import无论你引入多少次,只会导入一次
可改名:import * as a from \'xxx\'
有声明提升效果,import会自动提升到顶部
导出去模块内容,如果里面有定时器更改,外面也会改动,不像Common规范缓存
默认import语法不能写到if之类的语句中

另一种import的写法(返回的值是Promise对象):import(\'xxx\').then(res=>{...})
              优点:按需加载
                    可以写在if之类的语句中
                    路径也可以动态
可与Promise.all([])配合使用:Promise.all([import(\'xxxx1\'),import(\'xxxx2\')]).then(([m1,m2])=>{...});

与async,await配合:
async function(){
    const mod1=await import(\'xxxx1\');
    const mod2=await import(\'xxxx2\');
    const [m1,m2]=await Promise.all([import(\'xxxx1\'),import(\'xxxx2\')]).then();
}

export:
可在里面改名:export{a as apple,b as banana}

ES6 类和继承

类:
第一种方式:
class xxx{
    constructor(){
        this.xxx=\'xx\';
    }
    函数名(){},   //命名函数
    [变量名](){},  //表达式命名函数
}
第二种方式:
const xxx=class{...}

class里面的取值函数:get xxx(){}
           存值函数:set xxx(val){}
           
若想在class中直接使用类名调用里面方法,则在方法前面加上static 

注意:class没有声明提升的功能

继承:
extends,super()
class 子类名 extends 父类名{...}
e.g.1 class p{
        constructor(name){
            this.name=name;
        }
        showname(){
            return `${this.name}`
        }
     }
     
     class s extends p{
        constructor(name,skill){
            super(name);  //继承时必须写(继承参数)
            this.skill=skill;
        }
        showname(){
            super.showname(); //继承父级的方法
        }
        showskill(){
             return `${this.skill}`
        }
     }
     
e.g.2 拖拽
class Drag{
    constructor(id){
        this.odiv=document.getElementById(id);
        this.disX=0;
        this.disY=0;
        this.init();
    }
    init(){
        this.odiv.onmousedown=function(e){
            this.disX=e.clientX-this.odiv.offsetLeft;
            this.disY=e.clientY-this.odiv.offsetTop;
            
            document.onmousemove=this.Move.bind(this);
            document.onmouseup=this.Up.bind(this);
            return false;
        }.bind(this);
    }
    Move(e){
        this.odiv.style.left=e.clientX-this.disX+\'px\';
        this.odiv.style.top=e.clientY-this.disY+\'px\';
    }
    Up(){
        document.onmousemove=null;
        document.onmouseup=null;
    }
}

编写类LimitDrag(限制范围的拖拽,继承Drag)
class LimitDrag extends Drag{
    Move(e){
        super.Move(e);
        
        //在这里只编写左边和顶部的范围限制,其余两边可自行补充
        if(this.odiv.offsetLeft<=0){
            this.odiv.offsetLeft=0;
        }
        else if(this.odiv.offsetTop<=0){
            this.odiv.offsetTop=0;
        }
    }
}

ES6 Symbol和generator

Symbol定义:let syml=Symbol(\'xxx\');  (以数据类型symbol定义一个唯一值) 
注意:Symbol不能new
      Symbol返回是一个唯一值
      数据类型为symbol(以前的六个基本类型:number,string,boolean,function,object,undefined)
      若symbol作为key,用for in循环输不出来
      
generator函数:生成器(解决异步,深度嵌套的问题)
generator定义:function * xxx(){}
e.g. function * welcome(){
           yield \'hello\';
           yield \'world\';
           return \'friend\';
     }
     let w=welcome();
     //手动调用
     w.next(); => hello done:false
     w.next(); => world done:false
     w.next(); => friend done:true(证明生成器中的内容已全部输出完成)
     //自动调用
     for(let val of w){
        console.log(val); => hello world (但不会输出返回值)
     }
     //进行解构赋值
     let [a,b,c]=welcome();
     console.log(a,b,c); => hello world undefined
     //使用...运算符
     let [a,...b]=welcome();
     console.log(a,b);
     或直接console.log(...welcome());
     //使用Array.from
     console.log(Array.from(welcome()));
     
generator还可配合axios使用:
function * getdata(){
    let val=yield \'aa\';
    yield axios.get(\'xxxxxx${val}\');
}
let g=getdata();
let b=g.next().value;
g.next(b).value.then(res=>{...})

ES6 async和await

async function fn(){  //表示此函数有异步任务 
    await xxx   //表示后面的结果需要等待
}

async特点:
await只能放到async函数中
相比generator语义化更强
await后面可以是promise对象,也可以是数字,字符串,布尔
async函数返回是一个promise对象
只要await语句后面Promise状态变成reject,那么整个async函数都会中断执行 

解决async函数中抛出错误,影响后续代码:
第一种:
try{
}catch(e){
}
第二种:
promise本身的catch

建议:有await的地方,都放在try...catch...里面

ES6 Set和WeakSet

Set是一个新的数据结构
Set定义:let xxx = new Set() / new Set([\'a\',\'b\'])

Set的一些方法:
xxx.add(\'xx\'):往xxx添加一项xx
xxx.delete(\'xx\'):从xxx删除一项xx
xxx.has(\'xx\'):判断xxx中里面是否有xx
xxx.size:得出xxx的值的个数
xxx.clear:清空xxx的所有值
可用for...of... / xxx.forEach()循环xxx的值

可利用Set中的key值不能重复来实现数组去重:
let arr=[1,2,2,3,4,5,5,5,8,2];
let set=[...new Set(arr)];
此时的set为[1,2,3,4,5,8]

Set数据结构变成数组:[...set]

让set使用数组的map,filter方法:
let set= new Set([1,2,3]);
set=new Set([...set].map(val=>val*2))
set=new Set([...set].filter(val=>val%2==0))

WeakSet:(不推荐使用)
Set()里面最好放数组[],但可以直接利用add来把对象{}add进去(直接放就不行)
WeakSet()里面最好放对象{}
WeakSet没有size,clear方法

ES6 Map和WeakMap

Map定义:let map = new Map()

Map的一些方法:
map.set(key,value):设置一个值
map.get(key):获取一个值
map.delete(key):删除一个值
map.has(key):查看有没有那个值
map.clear():清空所有值
可用for...of... / xxx.forEach()循环值

WeakMap:
key只能是对象

ES6 数字(数值)变化和有关Math

数字(数值)变化:
生成二进制(Binary):let a = 0b10100
生成八进制(Octal):let a = 0o456
生成十六进制(Hex):let a = 0hccd

ES6新增的一些Number上的方法:
Number.isFinite(xx):判断xx是不是数字
Number.isInteger(xx):判断xx是不是整数
Number.isSafeInteger(xx):判断xx是否为安全整数
(安全整数的范围:-(2^53-1) ~ 2^53-1,包含两端)
Number.MAX_SAFE_INTEGER:显示最大安全整数
Number.MIN_SAFE_INTEGER:显示最小安全整数

 ES6新增的一些Math上的方法:
 Math.trunc():截断(只保留整数部分(不会四舍五入))
 Math.sign():判断一个数是正数(返回+1),负数(返回-1),还是0(返回0),其他值(返回NaN)
 Math.cbrt():计算一个数的开立方根
 

ES6 Proxy和Reflect

Proxy:代理(扩展对象的一些功能)

作用:vue中的拦截功能,预警,上报,扩展功能,增强...

语法:new Proxy(target,handler);
     let obj=new Proxy(被代理的对象,对代理对象进行什么操作) 
     handle: (部分方法操作)
     {
         set(target,prop,value){};  //设置,拦截
         get(target,prop){};  //获取
         deleteProperty(target,prop){}; //删除,拦截
         has(target,prop){};  //检测有没有某个东西
         apply(target,context,args){return Reflect.apply(...arguments)}; //调用函数处理
         ...
     }
    
 e.g. let obj={
            name=\'ckx\';
       }
       let newObj=new Proxy(obj,{
            get(target,property){
                console.log(\'你访问了${property}属性\')
                return target[property];
            }
       });
       console.log(newObj.name); => \'ckx\'
       
 e.g.1 实现一个功能:DOM.xxx()(xxx是什么就创建什么元素)
       const DOM = new Proxy({},{
            get(target,property){
                return function(attr={},...children){
                    //创建元素
                    const el = document.createElement(property);
                    //添加属性
                    for(let key of Object.keys(attr)){
                        el.setAttribute(key,attr[key])
                    }
                    //添加子元素
                    for(let child of children){
                        if(typeof(child)==\'string\'){
                            child=document.createTextNode(child);
                        }
                        el.appendChild(child);
                    }
                    return el;
                }
            }
       })
       let odiv=DOM.div({id:\'div1\',class=\'div2\'},\'我是div1\',\'和div2\')
       => <div id=\'div1\' class=\'div2\'>
            我是div1
            和div2
          </div>

Reflect:反射(通过Reflect对象身上直接拿到语言内部的东西)
Reflect.apply(调用的函数,this指向,参数数组)
e.g. let res=Reflect.apply(Math.ceil,null,[9.8]);
     console.log(res); => 10

\'assign\' in Object => Reflect.has(Object,\'assign\');

 delete json.a => Reflect.deleteProperty(json,\'a\');

ES2018(ES9)新增的东西

命名捕获:?<名字>
e.g. let str=\'2021-02-05\';
     let reg=/(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})/;
     let {year,month,day} = str.mathch(reg).groups;
     分别输出year,month,day为:2021,02,05
     
反向引用命名捕获:\\k<名字>
e.g. let reg=/^(?<world>hello)-\\k<world>)$/;
     let str=\'a-a\'; => false
     let str1=\'world-world\'; => false
     let str2=\'hello-hello\'; => true
     
     let reg=/^(?<world>hello)-\\k<world>-\\1)$/; => 匹配到的是:hello-hello-hello
     
替换:$<名字>
e.g. let str=\'2021-02-05\'; 
     let reg=/(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})/;
     str.replace(reg,\'$<year>/$<month>/$<day>\'); => 2021/02/05
另一种替换方式:str=str.replace(reg,(...args)=>{
                    let {year,month,day} = args[args.length-1];
                    retrun `${year}/${month}/${day}`;
               })
               => 2021/02/05
 
dotAll模式:s
在原来的正则中,\'.\'表示匹配任何东西,除了\\r,\\n (在es6里可以在正则表达式后面加上s,致使都能匹配)
e.g. let reg=/^\\w+.\\w+$/s;
     let str=hello\\nworld; => true
     
标签函数:
function xxx(args){
    console.log(args[0]); 
}
console.log(xxx`hello`);
输出为hello

关于异步的几种解决方案

回调函数
事件监听
发布/订阅
Promise对象

将ES6语法转换成ES5语法

1. nodesjs中的babel模块(babel-preset-es2015 babel-cli)
2. 新建文件.babelrc
3. 在新建的文件中编写:{
                        "presets":[
                            "es2015"
                        ],
                        "plugins":[]
                     }
4. 利用babel转化自己写的js文件(含ES6语法)
    babel src/index.js(自己写的文件) -o dist/index.js(目标文件)
    文件夹的转换:babel src(自己文件所在的文件夹) -d dist(转化后的文件所在的文件夹)
    想要实时的编译:babel src/index.js(自己写的文件)-w -o dist/index.js(目标文件)
    babel src(自己文件所在的文件夹)-w -d dist(转化后的文件所在的文件夹)
    

以上是对ES6的部分整理和总结,希望有用,有什么建议欢迎提出哦!
大家一起进步~

以上是关于关于ES6的主要内容,如果未能解决你的问题,请参考以下文章

关于代码片段的时间复杂度

关于阮一峰老师es6(第三版)中管道机制代码的理解浅析

关于ES6的数组字符串方法

关于片段生命周期

关于代码分割

关于js----------------分享前端开发常用代码片段