ES6 快速入门与使用

一、简介

  • ES6 -> ECMA 标准,又叫 ES2015。ES6 -> 2015年6月 ES6.0;

  • 每年6月份,发布一个版本

发布时间 版本 别名
2016年6月 ES6.1 ES7、ES2016
2017年6月 ES6.2(async await) ES8、ES2017
  • babel-loader 解析 ES6。
  • 所有 ES6 内容见:官方资料
  • chrome, 对新的语法支持,速度挺猛,一般在新语法发布的下一个版本中就会支持。
  • ES6环境:
    • webpack3.x --> babel-loader;
    • Traceur。

二、 let 和 const

  • 关于定义(声明)变量:

    • 之前:var a=12;
    • 现在:let a=12。
  • 之前作用域:

    • 全局;
    • 函数作用域。
  • 现在作用域:

    • 块级作用域。
  • 块级作用域:

    • ES5只有全局作用域和函数作用域,没有块级作用域。
      • 问题一:内层变量可能会覆盖外层变量;
      • 问题二:用来计数的循环变量泄露为全局变量。
1.let
  • let:用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效;
  • 不存在变量提升,所以变量一定要先声明后使用;
  • 暂时性死区(TDZ,temporal dead zone):ES6明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭的作用域,凡是在声明之前就使用这些变量,就会报错,并且不受外部的影响(即和外部有同样变量名的变量没有关系);
    • typeof不再安全,如果在声明之前调用typeof,会报错referenceError;而如果一个变量根本没有被声明,使用typeof反而不会报错。
  • 不允许重复声明:在同一作用域内,不允许重复声明同一个变量,即使使用var声明也不可以;for循环中,for 判断条件中的是父级作用域,循环体里面的是子作用域。
function func(arg){
    let arg;    //报错
}
function func2(arg){
    {
        let arg:    //不报错
    }
}
var arr = [];
for (var i=0;i<3;i++){
    var fun = function () {
        console.log(i);
    };
    arr.push(fun);
}

arr[1]();   //3
var arr = [];
for (let i=0;i<3;i++){
    var fun = function () {
        console.log(i);
    };
    arr.push(fun);
}

arr[1]();   //1
2.const
  • 声明一个只读的常量,一旦声明,常量的值就不可以更改;
  • 所以在声明变量的时候,就必须立即初始化,不得留着以后赋值;
  • const作用域和let一样,只在声明所在的块级作用域内有效;
  • 存在暂时性死区,只能在声明的位置后面使用;
  • 不可重复声明;
  • 对于复合类型的变量,变量名不指向数据,而是指向数据所在的地址。const命令只是保证变量名指向的地址不变,并不保证该地址的数据不变,所有将一个对象声明为常量时必须非常小心。如果想让一个对象冻结,可以使用Object.freeze()方法:Object.freeze(对象)
  • 立即执行函数: IIFE
    (function(){
        //TODO
    })()
  • 建议:
    • 以后 就用 let 不要在使用var
    • 不让后期修改的变量使用 const,如:const http = require('http');

三、解构赋值:

  • 非常有用,特别在做数据交互 ajax;
  • let [a,b,c] =[12,5,6];
  • 注意: 左右两边,结构格式要保持一致。
  • 数组的解构赋值和位置有关;而对象的解构赋值和位置没有关系,而是取决于它的变量名和属性名对应关系。
//解构json:
let json = {
    name:'YJW',
    age:18,
    job:'coding'
};
let {name,age,job} = json;  //其中 {} 中的名字要和 JSON 中的 key 必须对应,否则会找不到,结果为 undefined
console.log (name,age,job);  //YJW 18 coding
let {name:n,age:g, job:a} = json;
let json = {
    name:'YJW',
    age:18,
    job:'coding'
};
let {name:n,age:a, job:j} = json;  //给变量起别名,此时只能用别名,不能再使用 name、age、job,只能用别名
console.log (n,a,j);  //YJW 18 coding
  • 解构时候可以给默认值:
let [e,f,g] = [12,23];
console.log(e,f,g);  //12 23 undefined
let [e,f,g=34] = [12,23];
console.log(e,f,g);  //12 23 34
null 和 undefined 的区别:
let [e,f,g=34] = [12,23,undefined];
console.log(e,f,g);  //12 23 34
let [e,f,g=34] = [12,23,null];
console.log(e,f,g);  //12 23 null
 //说明如果值为 null 时,默认值不能生效
交换两个数的位置:
let h = 12;
let i = 5;
[h,i] = [i,h];
console.log(h,i);   //5 12
  • 用小括号 () 的情况:
let j;
({j} = {j:111});  //此处的 {j} 限定了作用域,如果不加小括号会报错
console.log(j);

四、字符串模板:

  • 字符串模板语法:两个反单引号 ``
  • 优点: 可以随意换行
  • 使用变量:${变量名字}
let name ='Strive';
let age = 18;
let str = `这个人叫${name}, 年龄是 ${age}岁`;
  • 练习:新闻列表



    
    string


    
    ES2016 新增的内容
    • 字符串查找:
      • str.indexOf(要找的东西):返回索引(位置) ,没找到返回-1。
      • str.includes(要找的东西):返回值 true/false。
        • 判断浏览器的包含信息:includes
    navigator.userAgent.includes("Chrome");
    
    • 字符串是否以谁开头:
      • str.startsWith(检测东西);
    • 字符串是否以谁结尾:
      • str.endsWith(检测东西);;例如检测文件后缀名.png等。
    • 重复字符串:
      • str.repeat(次数);
    "yjw".repeat(3);  //yjwyjwyjw
    
    • 字符串填充:
      • str.padStart(整个字符串长度, 填充东西):往前填充;
      • str.padEnd(整个字符串长度, 填充东西):往后填充;
      • 如果设定的整个字符串长度小于原来字符串长度,则不进行填充,得到的还是原字符串。
    let str = "aaa";
    let padStr = "bbb";
    console.log(str.padStart(str.length+padStr.length,padStr));  //bbbaaa
    console.log("321".padStart(6,'a'));    //"aaa321"
    console.log('321'.padStart(6,"abcdefg"));    //"abc321"
    console.log("321".padStart(2,"aaaaaaa"));    //"321"
    

    五、函数变化:

    1. 函数默认参数
    • 之前:
    function show(a,b) {
        a = a || "Wel ";
        console.log(a + b);
    }
    show("Welcome ","YJW");  //Welcome YJW
    show("Welcome ","");  //Welcome
    show("","YJW");  //Wel YJW
    
    • 现在:
    function show({x=0,y=0}={}){
        console.log(x,y);
    }
    show();
    
    函数参数默认已经定义了,函数的参数作用范围在函数体内,不能再使用let,const声明
    function show(a=18){
        let a = 101;  //错误
        console.log(a);
    }
    show()
    
    2. rest运算符(扩展运算符):...
    • 展开数组:
    var arr = [1,2,3,4,5];
    console.log(...arr);  //1 2 3 4 5
    
    • 合并为一个数组:...
    function arrSort(...a) {
        console.log(a.sort());    //[1, 2, 3, 8, 9]
    }
    arrSort(2,1,3,9,8);
    
    • 剩余参数:作为参数必须放到最后,如 show(a,b,...c);
    3. 箭头函数:=>
    • 箭头函数之前:
    function show1() {
        return 1;
    }
    console.log(show1());  //1
    
    • 箭头函数
    let show2 = ()=>1;
    console.log(show2());  //1
    
    • 格式:(参数) => return东西
    (参数) =>{
        语句
        return
    }
    
    • 注意:
      1. this 问题:this 指定义函数所在的对象,不在是运行时所在的对象;
      2. 箭头函数里面没有arguments,用 ‘...arg’
      3. 箭头函数不能当构造函数。
    function Person() {
        this.name = "yjw";
    }
    let pers = new Person();
    console.log(pers.name);
    
    let Person2 = ()=>{
        this.name = "yjw";
    };
    let person = new Person2();
    console.log(person.name);   //报错 Person2 is not a constructor
    

    六、数组

    1. ES5里面新增一些东西
    循环:
    • 之前:

      1. for:for(let i=0; i
      2. while
    • arr.forEach(回调函数):// 代替普通for

    var arr = ["apple","banana","pear"];
    arr.forEach(function (value,index) {
        console.log(value,index);
    });
    
    结果:
      apple 0
      banana 1
      pear 2
    

    其实它可以接受两个参数,arr.forEach/map/...(callback,this指向的值);

    • arr.map():// 非常有用,做数据交互 "映射"
      • 正常情况下,需要配合 return,返回是一个新的数组;
      • 若是没有 return,相当于 forEach
      • 注意:平时只要用map,一定是要有return
      • 练习:重新整理数据结构:[{title:'aaa'}] -> [{t:'aaaa'}]
    let newsArr = [
        {title:"2018博鳌亚洲论坛年会",read:12},
        {title:"中朝启动志愿军烈士陵园修缮工程 ",read:33},
        {title:"捍卫国家利益,我们有底气!",read:44},
        {title:"中国是亚洲经济增长的重要后盾",read:55},
        {title:"美国的任性行为破坏国际贸易秩序 损人不利己",read:66}
    ];
    let newArr = newsArr.map(function (value,index) {
        let json = {};
        json.t = `hei${value.title}`;
        json.r = value.read+100;
        return json;
    });
    console.log(newArr);
    
    结果:
      [{t: "hei2018博鳌亚洲论坛年会", r: 112},
       {t: "hei中朝启动志愿军烈士陵园修缮工程 ", r: 133},
       {t: "hei捍卫国家利益,我们有底气!", r: 144},
       {t: "hei中国是亚洲经济增长的重要后盾", r: 155},
       {t: "hei美国的任性行为破坏国际贸易秩序 损人不利己", r: 166}]
    
    • arr.filter():过滤,过滤一些不合格“元素”,如果回调函数返回 true,数组中的这条数据就会留下来。
    let newsArr = [
        {title:"2018博鳌亚洲论坛年会",read:12,top:true},
        {title:"中朝启动志愿军烈士陵园修缮工程 ",read:33,top:true},
        {title:"捍卫国家利益,我们有底气!",read:44,top:false},
        {title:"中国是亚洲经济增长的重要后盾",read:55,top:true},
        {title:"美国的任性行为破坏国际贸易秩序 损人不利己",read:66,top:false}
    ];
    let newArr = newsArr.filter(function (value,index) {
        return value.top;
    });
    console.log(newArr);
    
    结果:
      [{title: "2018博鳌亚洲论坛年会", read: 12, top: true},    
       {title: "中朝启动志愿军烈士陵园修缮工程 ", read: 33, top: true},
       {title: "中国是亚洲经济增长的重要后盾", read: 55, top: true}]
    
    • arr.some():类似查找, 查找数组里面某一个元素是否符合条件,如果符合就返回true。
    let newsArr = [
        {title:"2018博鳌亚洲论坛年会",read:12,top:true},
        {title:"中朝启动志愿军烈士陵园修缮工程 ",read:33,top:true},
        {title:"捍卫国家利益,我们有底气!",read:44,top:false},
        {title:"中国是亚洲经济增长的重要后盾",read:55,top:true},
        {title:"美国的任性行为破坏国际贸易秩序 损人不利己",read:66,top:false}
    ];
    let newArr = newsArr.some(function (value,index) {
        return value.top;
    });
    console.log(newArr);
    
    结果:true。
    
    • arr.every():数组里面所有的元素都符合条件,才返回 true,否则返回 false。
    let newsArr = [
        {title:"2018博鳌亚洲论坛年会",read:12,top:true},
        {title:"中朝启动志愿军烈士陵园修缮工程 ",read:33,top:true},
        {title:"捍卫国家利益,我们有底气!",read:44,top:false},
        {title:"中国是亚洲经济增长的重要后盾",read:55,top:true},
        {title:"美国的任性行为破坏国际贸易秩序 损人不利己",read:66,top:false}
    ];
    let newArr = newsArr.every(function (value,index) {
        return value.top;
    });
    console.log(newArr);
    
    结果:false。
    
    • 以上所有函数都可以接收两个参数:arr.forEach/map...(循环回调函数, this指向谁);

    • arr.reduce()://从左往右
      • 使用:求数组的和、阶乘、乘方等
    let arrNum = [2,3,4,5];
    let result = arrNum.reduce(function (accumulator, cur, curIndex, arr) {
        //accumulator 为上一次 return 的值,第一次循环时返回的为数值中第一个值
        //cur 为当前数组的值
        //curIndex 为当前的索引
        //arr 为调用这个方法的数组
        console.log("pre:  "+accumulator);
        console.log("cur:  "+cur);
        console.log("val:  "+curIndex);
        console.log("index:"+arr);
        return (accumulator+cur)
    });
    console.log(result);
    
    pre:  2
    cur:  3
    val:  1
    index:2,3,4,5
    pre:  5
    cur:  4
    val:  2
    index:2,3,4,5
    pre:  9
    cur:  5
    val:  3
    index:2,3,4,5
    14
    
    • arr.reduceRight(): //从右往左
    let arrNum = [1,3,5,7];
    let result = arrNum.reduceRight(function (accumulator, cur, curIndex, arr) {
        //accumulator 为上一次 return 的值,第一次循环时返回的为数值中最后一个值
        //cur 为当前数组的值
        //curIndex 为当前的索引
        //arr 为调用这个方法的数组
        console.log("pre:  "+accumulator);
        console.log("cur:  "+cur);
        console.log("val:  "+curIndex);
        console.log("arr:  "+arr);
        return (accumulator+cur)
    });
    console.log(result);
    
    pre:  7
    cur:  5
    val:  2
    arr:  1,3,5,7
    pre:  12
    cur:  3
    val:  1
    arr:  1,3,5,7
    pre:  15
    cur:  1
    val:  0
    arr:  1,3,5,7
    16
    
    • ES2017新增一个运算符:幂(**)
      • Math.pow(2,3) = 2 ** 3
    2. ES6:
    • for....of....
      • arr.keys():数组下标;
      • arr.entries():数组中的每一项(包含下标和值);
    let arrNum = ["apple","banana","pear"];
    for (let value of arrNum){
        console.log(value);
    }
    //apple
    //banana
    //pear
    
    let arrNum = ["apple","banana","pear"];
    for (let key of arrNum.keys()){
        console.log(key);
    }
    //0
    //1
    //2
    
    let arrNum = ["apple","banana","pear"];
    for (let entry of arrNum.entries()){
        console.log(entry);
    }
    //[0, "apple"]
    //[1, "banana"]
    //[2, "pear"]
    
    let arrNum = ["apple","banana","pear"];
    for (let [key,val] of arrNum.entries()){
        console.log(key,val);
    }
    //0 "apple"
    //1 "banana"
    //2 "pear"
    
    • 扩展运算符:...
    let arr =[1,2,3];
    let arr2 = [...arr];
    let arr3 = Array.from(arr);
    //arr2 和 arr3 结果一样。
    
    Array.from:
      作用: 把类数组(一组元素、arguments...) 对象`转成数组`
      暂时发现:具备 length这个东西,就靠谱。比如 JSON 没有 length,但是在 JSON 中添加 `length:2` 就可以解决问题。
    
    • Array.of():把一组值,转成数组
    let arr = Array.of("aaa","bbb","ccc");
    console.log(arr);    //["aaa", "bbb", "ccc"]
    
    • arr.find(): 查找,找出第一个符合条件的数组成员,如果没有找到,返回undefined
    let arr = [12,120,13,101];
    let num = arr.find(function (val,index) {
        return val>100;
    });
    console.log(num);    //120
    
    • arr.findIndex():找的是位置, 没找到返回-1
    let arr = [12,120,13,101];
    let num = arr.findIndex(function (val,index) {
        return val>100;
    });
    console.log(num);  //1
    
    • arr.fill():填充
      • 用法:arr.fill(填充的东西, 开始位置, 结束位置);
    let arr = new Array(5);
    arr.fill("aa",1,3);
    console.log(arr);  //[empty × 1, "aa", "aa", empty × 2]
    
    • 在ES2016里面新增:
      • arr.indexOf();
      • arr.includes();
      • str.includes();
    let str = "abcdefg";
    console.log(str.includes("cd"));  //true
    let arr = ["a","b","c","d"];
    console.log(arr.indexOf("c"));  //2
    console.log(arr.includes("c")); //true 
    

    七、对象:

    • 对象简洁语法(相当有用):
    //之前用法
    let a = 1;
    let b = 2;
    let json ={
        a:a,
        b:b,
        showA:function(){
            return this.a;
        }
        showB:function(){
            return this.b;
        }
    }
    
    //现在用法
    let json ={
        a,
        b,
        showA(){  //个人建议: 一定注意,不要用箭头函数
        },
        showB(){
        }
    }
    
    new Vuex.Store({
        state,
        mutation,
        types,
        actions
    });
    
    new Vue({
        router,
        App,
        vuex
    });
    
    • Object.is():用来比较两个值是否相等
      • 语法:Object.is('a','a');
    console.log(NaN == NaN);  //false
    console.log(Number.isNaN(NaN));  //true
    console.log(Object.is(NaN,NaN));  //true
    
    console.log(+0 == -0);  //true
    console.log(Object.is(+0,-0));  //false
    console.log(Object.is("aaa","aaa"));  //true
    
    • Object.assign():用来合并对象、复制对象
      • 语法:let 新的对象 = Object.assign(目标对象, source1, srouce2....);
    let a = {a:1};
    let b = {b:2,a:2};  // 有重复变量时,后面的会覆盖前面的
    let c = {c:3};
    let json = Object.assign({},a,b,c);
    console.log(json);    // {a: 2, b: 2, c: 3}
    
    • 使用:
    function ajax(options){  // options 为用户传的参数
        let defaults={
            type:'get',
            header:
            data:{}
            ....
        };
    
        let json = Object.assign({}, defaults, options);
        .....
    }
    
    let arr = ["a","b","c"];
    let newArr = Object.assign([],arr);
    newArr.push("dd");
    console.log(arr);    //["a", "b", "c"]
    console.log(newArr);    //["a", "b", "c", "dd"]
    
    • 用途:
      1. 复制一个对象;
      2. 合并参数。
    ES2017引入:
    • Object.keys(obj);
    • Object.entries(obj);
    • Object.values(obj);
    let json = {
        a:111,
        b:222,
        c:333
    };
    console.log(Object.keys(json));  // ["a", "b", "c"]
    console.log(Object.values(json));  // [111, 222, 333]
    console.log(Object.entries(json));  // [["a", 111],["b", 222],["c", 333]]
    
    let {keys, values, entries} = Object;
    for (let key of keys(obj){
        ....
    }
    
    • 扩展运算符:...,计划在ES2018引入
    let json = {
        a:111,
        b:222,
        c:333,
        d:444
    };
    
    let {a,b,...c} = json;
    console.log(a,b,c);  //111 222 {c: 333, d: 444}
    
    let json = {
        a:111,
        b:222,
        c:333,
        d:444
    };
    let newJson = {...json};
    delete newJson.a;
    console.log(newJson);  //{b: 222, c: 333, d: 444}
    console.log(json);  //{a: 111, b: 222, c: 333, d: 444}
    

    八、Promise

    • 作用: 解决异步回调问题
    • 传统方式,大部分用回调函数,事件:
    ajax(url,{  //获取token
        ajax(url,()=>{  //获取用户信息
            ajax(url, ()=>{
                //获取用户相关新闻
            })
        })
    })
    
    • Promise 基本语法:
    let promise = new Promise(function(resolve, reject){
        //resolve,   成功调用
        //reject     失败调用
    });
    
    promise.then(res=>{
        //成功时候执行这里
        ....  
    }, err=>{
        //失败时候执行这里
        ....
    });
    
    promise.catch(err=>{
        //失败时候会执行这里
        ....
    })
    
    let a = 1;
    let promise = new Promise(function (resolve, reject) {
        if (a == 10){
            resolve("成功啦。。。");
        }else {
            reject("失败了。。。");
        }
    });
    
    promise.then(res=>{
        console.log(res);
    },err=>{
        console.log(err);
    });
    promise.catch(err=>{
        console.log(err);
    });
    // 失败了。。。
    // 失败了。。。
    // 如果 let = 10;会打印 “成功啦。。。”
    
    • 因为 promise.then 中失败的回调方法和 promise.catch 中失败的回调方法一样,此处只需调用一个即可:
    new Promise().then(res=>{
        ....
    }).catch(err=>{
        ....
    })
    
    let a = 10;
    let promise = new Promise(function (resolve, reject) {
        if (a == 10){
            resolve("成功啦。。。");
        }else {
            reject("失败了。。。");
        }
    }).then(res=>{
        console.log(res);
    }).catch(err=>{
        console.log(err);
    });
    // 成功啦。。。
    
    • Promise.resolve('aa'):将现有的东西,转成一个promise对象, resolve 状态,成功状态。等价于:
    new Promise(resolve =>{
        resolve('aaa')
    });
    
    • Promise.reject('aaa'):将现有的东西,转成一个promise 对象,reject 状态,失败状态。等价于:
    new Promise((resolve, reject) =>{
        reject('aaa')
    });
    
    let p1 = Promise.resolve("succ--哈哈哈");
    let p2 = Promise.reject("fail--嘿嘿嘿");
    p1.then(res=>{
        console.log(res);    // succ--哈哈哈
    });
    p2.then(res=>{
        console.log(res);
    },err=>{
        console.log(err);   // fail--嘿嘿嘿
    });
    
    • 批量处理函数:Promise.all([p1, p2, p3]):把 promise 打包,扔到一个数组里面,打包完还是一个promise对象。
    let p1 = Promise.resolve("aaa");
    let p2 = Promise.resolve("bbb");
    let p3 = Promise.resolve("ccc");
    
    Promise.all([p1,p2,p3]).then(res=>{
        console.log(res);
    }).catch(err => {
        console.log(err);
    })
    // ["aaa", "bbb", "ccc"]
    
    必须确保,所有的promise对象,都是resolve状态,都是成功状态,否则只会返回失败的那个信息
    
    let p1 = Promise.resolve("aaa");
    let p2 = Promise.resolve("bbb");
    let p3 = Promise.reject("ccc");
    
    Promise.all([p1,p2,p3]).then(res=>{
        console.log(res);
    }).catch(err => {
        console.log(err);
    });
    // ccc
    
    • Promise.race([p1, p2, p3]):只会返回第一个
    let p1 = Promise.reject("aaa");
    let p2 = Promise.resolve("bbb");
    let p3 = Promise.resolve("ccc");
    
    Promise.race([p1,p2,p3]).then(res => {
        console.log(res);
    }).catch(err => {
        console.log(err);
    });
    //aaa
    
    • 执行顺序比较:
    new Promise(function (resolve, reject) {
        console.log("1111");
    
        resolve("22222");
    
        new Promise(function (resolve, reject) {
            resolve("333333")
        }).then(function (res) {
            console.log(res);
        });
    
        setTimeout(function () {
            console.log("44444");
        },0);
    
        console.log("66666");
        
    }).then(res => {
        console.log(res)
    });
    
    console.log("55555");
    
    结果:
        1111
        66666
        55555
        333333
        22222
        44444
        // 发现定时器是最后执行的
    
    • 使用实例:用户登录 -> 用户信息。

    九、模块化

    • js 不支持模块化;
    • 其它语言中:
      • ruby --> require
      • python --> import
    • 在ES6之前,社区制定一套模块规范:
      • Commonjs:主要服务端 nodeJs,如:require('http');
      • AMD:requireJs, curlJs
      • CMD:seaJs
    • ES6出来,统一服务端和客户端模块规范:import {xx} ddd
    模块化:
    • 注意: 需要放到服务器环境
    • 如何定义模块?
    ① export  东西
    ② export const a =12;
    ③ export{
          a as aaa,    // 以后导入的时候只能导入 aaa  :import {aaa} from "./a.js";
          b as banana    // 以后导入的时候只能导入 banana
       }
    ④ export default aaa;  // 导入的方式不需要 {}:import aaa from "./a.js";
    
    • 如何使用?
    
    
    • import:特点
      a. import 可以是相对路径,也可以是绝对路径:import “https://code.jquery.com/jquery-3.3.1.js”;
      b. import 模块实际上只会导入一次,无论你引入多少次;
      c. import './modules/1.js'; 如果这么用,相当于引入文件,要的不是这个效果,而是:import {a} form './modules/1.js';
      d. 有提升效果,import 会自动提升到顶部,首先执行;
      e. 导出去模块内容,如果里面有定时器更改,外面也会改动,不像 Common 规范缓存。

    • 默认 import 语法不能写到 if 之类里面,即不能根据条件去有选择性的导入某个文件。

    • import():类似 node 里面 require, 可以动态引入,返回值,是个 promise 对象,可以采用 promise 规范:

      //这样就可以根据条件加载了
      function result(a){
          switch(a){
            case 1:
                return "./1.js";
                break;
            case ...
          }
      }
      import(result(1)).then(res=>{
        console.log(res.a+res.b);
      });
      
      优点:
        1. 按需加载
        2. 可以写if中
        3. 路径也可以动态
      
    Promise.all([import("./1.js"),import("./2.js")]).then(([mod1,mod2]) => {
        console.log(mod1);
        console.log(mod2);
    });
    
    • ES2017 加 async await,import 可以配合这两个使用。
    • use strict:以后默认就是严格模式。

    十、类和继承

    • ES6 之前:函数模拟。
    人:  Person
        属性: name
        展示名字: showName
    
        Person.prototype.showName
    
    function Person(name,age){
      this.name='aaa';
      this.age = age;
    }
    Person.prototype.showName=function(){
      return `名字是:${this.name}`;
    }
    let p1 = new Person("yjw",18);
    
    程序中类
    • ES6
    面向对象 ,类
        属性
        方法
    

    ES6中变形:

        class Person{
            constructor(name,age){  //构造方法(函数),调用 new 时,自动执行
                this.name = name;
                this.age = age
            } 
            showName(){
                return `名字是:${this.name}`;
            }
        }
        let p = new Person("yjw",18);
    
    • 其它定义格式:const Person = class{}
    let name = "yjw";
    class Person{
        [name](){
            console.log("haha "+name);
        }
    }
    let p = new Person();
    p[name]();  //haha yjw
    // [] 中放变量名,这样通过 [] 就可以变成一个属性,属性名可以是表达式
    
    • 注意:
      1. ES6 里面 class 没有提升功能,在 ES5,用函数模拟可以,默认函数提升;
      2. ES6 里面 this 比之前轻松多了。
    • 矫正this:

      1. fn.call(this指向谁, args1, args2....) // 函数执行时才会绑定;
      2. fn.apply(this指向谁, [args1, args2....]) // 函数执行时才会绑定;
      3. fn.bind()。
    • class里面取值函数(getter), 存值函数(setter)

    class Person{
        set name(val){
            console.log(`设置了 name 的值,值为:${val}`);
        }
    
        get name(){
            return `获得了 name 属性的值`;
        }
    }
    
    let p = new Person();
    p.name = "yjw";    //设置了 name 的值,值为:yjw
    console.log(p.name);    //获得了 name 属性的值
    
    • 静态方法:就是类身上方法,在方法名前加 static 即可:
    class Person{
        showName(){
            return "展示 name";
        }
        static showLog(){
            return "展示 静态方法";
        }
    }
    
    let p = new Person();
    console.log(p.showName());    //展示 name
    console.log(Person.showLog());    //展示 静态方法
    
    继承:
    // 之前:
    function Person(name) {
        this.name = name;
    }
    Person.prototype.showName = function () {
        return `名字是:${this.name}`;
    };
    
    function Student(name, skill) {
        Person.call(this,name);  // 继承 name 属性
        this.skill = skill;
    }
    
    Student.prototype = new Person();   // 继承方法
    
    let p = new Person("yjw");
    console.log(p.showName());  //名字是:yjw
    
    let s = new Student("wang");
    console.log(s.name);  //wang
    console.log(s.showName());  //名字是:wang
    
    //现在: extends
    class Person{
        constructor(name){
            this.name = name;
        }
        showName(){
            return `名字是:${this.name}`;
        }
    }
    
    class Student extends Person{
        constructor(name,skill){
            super(name);
            this.skill = skill;
        }
    }
    
    let s = new Student("yjw","study");
    console.log(s.name);    //yjw
    console.log(s.showName());  //名字是:yjw
    console.log(s.skill);   //study
    
    • 拖拽

    十一、Symbol

    • ES6 多一个数据类型 Symbol(首字母一定要大写);
    • 使用频率不高,node 底层可能会用到;
    • 定义:
    let sym = Symbol("aaa");
    console.log(sym);    //Symbol(aaa)
    console.log(typeof sym);    //symbol,用 typeof 检测出来数据类型:symbol
    
    • 注意:
      1. Symbol 不能 new;

      2. Symbol() 返回一个唯一值:做一个 key,定义一些唯一或者私有一些东西;

      3. symbol 是一个单独数据类型,就叫 symbol,是一个基本类型。所有数据类型:number、string、boolean、symbol、undefined、Object、function。

      4. 如果 symbol 作为 key ,用 for in 循环,会出不来。

    let sym = Symbol("aaa");
    let json = {
        a:"aaa",
        b:"bbb",
        [sym]:"symbol"
    };
    for (let key in json){
        console.log(key);
    }
    
    //结果
    a
    b
    

    十二、generator 函数

    • 生成器;

    • 解决异步深度嵌套的问题,但是现在多用 async 解决异步问题(后面会讲);

    • 语法:

    // 方法一:
    function * show(){
        yield
    }
    //方法二
    function* show(){
        yield
    }
    //方法三
    function *show(){
        yield
    }
    
    //使用
    function * gen() {
        yield 111111;
        yield (function () {return 2222;})();
        return 33333;
    }
    
    let g = gen();
    console.log(g.next());  //{value: 111111, done: false}
    console.log(g.next());  //{value: 2222, done: false}
    console.log(g.next());  //{value: 33333, done: true}
    console.log(g.next());  //{value: undefined, done: true}
    
    console.log(gen().next());  //{value: 111111, done: false}
    console.log(gen().next());  //{value: 111111, done: false}
    
    • 上述调用,手动调用,麻烦:可以配合 for .. of 自动遍历 generator
    function * gen() {
        yield 111111;
        yield (function () {return 2222;})();
        yield 333333;
        return 444444;
        yield 555555;
    }
    
    for (let val of gen()){
        console.log(val);
    }
    
    111111
    2222
    333333
    // return 的东西,不会被遍历
    //并且 return 后面的数据也不会被遍历,yield 中的 return 不会被影响
    
    • generator 不仅可以配合 for ... of ...,还可以与其它配合使用。
    • 解构赋值:
    function * gen() {
        yield 111111;
        yield (function () {return 2222;})();
        yield 333333;
        return 444444;
        yield 555555;
    }
    
    let [a,b,c,d] = gen();
    console.log(a, b, c, d);  //111111 2222 333333 undefined
    
    1. 扩展运算符:...
    function * gen() {
        yield 111111;
        yield (function () {return 2222;})();
        yield 333333;
        return 444444;
        yield 555555;
    }
    
    let [a,...b] = gen();
    console.log(a, b);
    // 111111 [2222, 333333]
    
    • Array.from():
    function * gen() {
        yield 111111;
        yield (function () {return 2222;})();
        yield 333333;
        return 444444;
        yield 555555;
    }
    
    let arr =Array.from(gen());
    console.log(arr);  //[111111, 2222, 333333]
    
    • generator结合 axios数据请求:

    十三、async

    • 异步:不连续,上一个操作没有执行完,下一个操作照样开始;

    • 同步:连续执行,上一个操作没有执行完,下一个没法开始。

    • 关于异步,解决方案:
      a). 回调函数
      b). 事件监听
      c). 发布/订阅 (emit/on)
      d). Promise对象
      自动执行的库:co....等等

    • ES2017,规定 async。在函数名前面加 async,在函数里面配合 await 使用,意在说明 await 后面的操作是耗时的,不能立刻返回结果。

    async function fn(){  //表示异步,这个函数里面有异步任务
        let result = await  xxx //表示后面结果需要等待    
    }
    
    nodeJs 中读取文件 fs.readFile。
    • 首先创建三个文件:aaa.txt(里面存有aaaaaaaaaaaaaaaaaaaaaaaaaaaaa)、bbb.txt(里面存有bbbbbbbbbbbbb)、ccc.txt(里面存有cccccccccccc)
    //1. promise
    let fs = require("fs");
    
    let read = function (fileName) {
        return new Promise((resolve,reject) => {
            fs.readFile(fileName,function (err,res) {
                if (err) reject(err);
                resolve(res)
            });
        });
    };
    
    read("./aaa.txt").then(res=>{
        console.log(res.toString());
        return read("./bbb.txt");
    }).then(res=>{
        console.log(res.toString());
        return read("./ccc.txt");
    }).then(res=>{
        console.log(res.toString());
    });
    //aaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    //bbbbbbbbbbbbb
    //cccccccccccc
    
    //2. genrator
    let fs = require("fs");
    
    let read = function (fileName) {
        return new Promise((resolve,reject) => {
            fs.readFile(fileName,function (err,res) {
                if (err) reject(err);
                resolve(res)
            });
        });
    };
    
    function * gen(){
        yield read("./aaa.txt");
        yield read("./bbb.txt");
        yield read("./ccc.txt");
    }
    let g = gen();
    g.next().value.then(res => {
        console.log(res.toString());
        return g.next().value;
    }).then(res => {
        console.log(res.toString());
        return g.next().value;
    }).then(res => {
        console.log(res.toString());
    });
    //aaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    //bbbbbbbbbbbbb
    //cccccccccccc
    
    //3. async
    let fs = require("fs");
    
    let read = function (fileName) {
        return new Promise((resolve,reject) => {
            fs.readFile(fileName,function (err,res) {
                if (err) reject(err);
                resolve(res)
            });
        });
    };
    async function fn() {
        let f1 = await read("./aaa.txt");
        console.log(f1.toString());
    
        let f2 = await read("./bbb.txt");
        console.log(f2.toString());
    
        let f3 = await read("./ccc.txt");
        console.log(f3.toString());
    }
    
    fn();
    //aaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    //bbbbbbbbbbbbb
    //cccccccccccc
    
    • async 特点:
      1. await 只能放到 async 函数中;
      2. 相比 genrator 语义化更强;
      3. await 后面可以是 promise 对象,也可以数字、字符串、布尔;
      4. async 函数返回是一个 promise 对象;
      5. 只要 await 语句后面 Promise 状态变成 reject,那么整个 async 函数会中断执行。

    如何解决async函数中抛出错误,影响后续代码:
    a).
    try{

        }catch(e){
            
        }
    b). promise本身catch
    

    个人建议大家:
    try{
    let f1 = await readFile('data/a.txt');
    let f3 = await readFile('data/c.txt');
    let f2 = await readFile('data/b.txt');
    }catch(e){}


    async await

    数据结构
    数组
    json, 二叉树....

    set数据结构:
    类似数组,但是里面不能有重复值

    let arr = ['a','b','a'];

    let arr = new Array();

    set用法:
    let setArr = new Set(['a','b']);

    setArr.add('a');   往setArr里面添加一项
    setArr.delete('b'); 删除一项
    setArr.has('a') 判断setArr里面有没有此值
    setArr.size 个数
    
    setArr.clear(); 清空
    

    for...of...

    循环:
        a). for(let item of setArr){  //默认是values()
                    console.log(item);
                }
        b). for(let item of setArr.keys()){console.log(item);}
        c). for(let item of setArr.values()){}
        d). for(let [k,v] of setArr.entries()){}
        
        e). setArr.forEach((value,index) =>{
                    console.log(value, index);
                });
    

    let setArr = new Set().add('a').add('b').add('c');

    数组去重:
    let arr = [1,2,3,4,5,6,7,6,5,4,3,2,1,2,3,4,4];
    let newArr = [...new Set(arr)];
    console.log(newArr);

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

    想让set使用数组的,map循环和filter:


    let arr = [{},{}];

    new Set([]); 存储数组, 这种写法对

    new WeakSet({}) 存储json,这种写法不靠谱

    WeakSet没有size,也没有clear()
    
    有, add(), has(), delete()
    

    确认,初始往里面添加东西,是不行的。最好用add添加

    总结: new Set()

    let json ={
    p1:1,
    b:2
    };


    map:
    类似 json, 但是json的键(key)只能是字符串

    map的key可以是任意类型
    

    使用:
    let map = new Map();

    map.set(key,value);    设置一个值
    
    map.get(key)    获取一个值
    
    map.delete(key) 删除一项
    
    map.has(key)    判断有没有
    
    map.clear() 清空
    

    循环:
    for(let [key,value] of map){}

    for(let key of map.keys()){}
    
    for(let value of map.values()){}
    
    for(let [k,v] of map.entries()){}
    
    map.forEach((value, key) =>{
        console.log(value, key);
    })
    

    WeakMap(): key只能是对象


    总结:
    Set 里面是数组,不重复,没有key,没有get方法
    Map 对json功能增强,key可以是任意类型值


    十四、数字(数值)变化:

    二进制和八进制表示法:
    • 二进制: (Binary),使用 0b 或 0B 表示,0b010101;
    • 八进制: (Octal),使用 0o 或 0O 表示,0o666;
    • 将二进制或者八进制的数转化为十进制的数:Nunber(0o777);
    Number.isNaN(NaN) -> true

    Number.isFinite(a) 判断是不是数字 √
    Number.isInteger(a) 判断数字是不是整数 √

    -------------------------------------------
    Number.parseInt();
    Number.parseFloat();
    

    安全整数:
    2**3

    安全整数:    -(2^53-1) 到 (2^53-1),   包含-(2^53-1) 和(2^53-1)
    
    Number.isSafeInteger(a);
    
    Number.MAX_SAFE_INTEGER 最大安全整数
    Number.MIN_SAFE_INTEGER 最小安全整数
    

    Math:
    Math.abs()
    Math.sqrt()
    Math.sin()

    Math.trunc()    截取,只保留整数部分
        Math.trunc(4.5)  ->  4
        Math.trunc(4.9)  ->  4
    
    Math.sign(-5)   判断一个数到底是正数、负数、0
        Math.sign(-5)  ->  -1
        Math.sign(5)  -> 1
        Math.sign(0)    ->  0
        Math.sign(-0)   ->  -0
        其他值,返回 NaN
    
    Math.cbrt() 计算一个数立方根
    
        Math.cbrt(27)  ->  3
    
    .......
    

    ES2018(ES9):
    1. 命名捕获
    语法: (?<名字>)

        let str = '2018-03-20';
        let reg = /(?\d{4})-(?\d{2})-(?\d{2})/;
        let {year, month ,day} = str.match(reg).groups;
        console.log(year, month, day);
    反向引用:
        \1  \2     $1  $2
    反向引用命名捕获:
        语法:  \k<名字>
    
        let reg = /^(?welcome)-\k$/;
    
        匹配: ‘welcome-welcome’
    
        -------------------------------------------------
    
        let reg = /^(?welcome)-\k-\1$/;
    
        匹配: 'welcome-welcome-welcome'
    
    替换:
        $<名字>
    
        let reg = /(?\d{4})-(?\d{2})-(?\d{2})/;
        str = str.replace(reg,'$/$/$');
        console.log(str);
    
        ----------------------------------------
        str = str.replace(reg, (...args)=>{
            //console.log(args)
            let {year, month, day} = args[args.length-1];
    
            return `${day}/${month}/${year}`;
        });
    
        console.log(str);
    
    2.   dotAll 模式  s
    
        之前 '.' 在正则里表示匹配任意东西, 但是不包括 \n 
    
       let reg = /\w+/gims;
    
    3. 标签函数
        function fn(){
    
        }
    
        fn()  //这样调用就是普通函数
    
        fn`aaa`  //标签函数使用
    
        -----------------------------------
        function fn(args){
            return args[0].toUpperCase();
        }
    
        console.log(fn`welcome`);
    

    ES2018(ES9)

    proxy: 代理
    扩展(增强)对象、方法(函数)一些功能

    比如: 
        Vue
    
        Vue.config.keyCodes.enter=65
    
    Proxy作用: 比如vue中拦截
        预警、上报、扩展功能、统计、增强对象等等
    
    proxy是设计模式一种,  代理模式
    

    let obj ={
    name:'Strive'
    };
    //您访问了name
    obj.name // Strive


    语法:
    new Proxy(target, handler);
    let obj = new Proxy(被代理的对象,对代理的对象做什么操作)

    handler:
    
    {
        set(){},  //设置的时候干的事情
        get(){},  //获取干的事情
        deleteProperty(){},  //删除
        has(){}  //问你有没有这个东西  ‘xxx’ in obj
        apply()  //调用函数处理
        .....
    }
    

    实现一个,访问一个对象身上属性,默认不存在的时候给了undefined,希望如果不存在错误(警告)信息:


    DOM.div()
    DOM.a();
    DOM.ul()


    set(), 设置,拦截:
    设置一个年龄,保证是整数,且范围不能超过200

    deleteProperty(): 删除,拦截:

    has(): 检测有没有

    apply() :拦截方法


    Reflect.apply(调用的函数,this指向,参数数组);

    fn.call()
    fn.apply() 类似

    Reflect: 反射
    Object.xxx 语言内部方法

        Object.defineProperty
    
    放到Reflect对象身上
    
    通过Reflect对象身上直接拿到语言内部东西
    
    'assign' in Object    ->   Reflect.has(Object, 'assign')
    
    delete json.a       ->   Reflect.deleteProperty(json, 'a');
    

    你可能感兴趣的:(ES6 快速入门与使用)