• ES6学习之二


    本文的学习来自技术胖大神的教程:https://jspang.com/ 

    1扩展运算符和rest运算符

    扩展运算符和rest运算符,它们都是…(三个点)。

    它们有很多相似之处,甚至很多时候不用特意去区分。

    它们可以很好的解决参数和对象数组未知情况下的编程,让代码更健壮和简洁。

    1.1对象扩展运算符(…)

    当编写一个方法时,允许它传入的参数是不确定的。这时候可以使用对象扩展运算符来作参数。

    例:

    function test(...arg){
        console.log(arg[0]);
        console.log(arg[1]);
        console.log(arg[2]);
        console.log(arg[3]);
    }            
    test(1,2,3);

      

    说明可以传入多个值,并且就算方法中引用多了也不会报错。

    1.2扩展运算符的用处

    例1:声明两个数组arr1和arr2,然后把arr1赋值给arr2,然后改变arr2的值:

    let arr1=['a','b','c'];
    let arr2=arr1;
    console.log(arr2);
    arr2.push('d');
    console.log(arr1);

     

    可以看到arr1的值也改变了,因为这是对内存堆栈的引用,而不是真正的赋值。

    利用对象扩展运算符简单的解决这个问题:

    let arr1=['a','b','c'];
    let arr2=[...arr1];
    console.log("arr2:",arr2);
    arr2.push('d');
    console.log("arr1:",arr1);
    console.log("arr2:",arr2);

    可以看到arr1并没有改变。

    1.3 rest运算符

    例:

    function test(first,...arg){
        console.log(arg.length);
    }
    test(1,2,3,4,5,6);

    第一个参数1传给了first,剩下的参数传给了arg数组,所以arg长度为5

    1.4循环输出rest运算符

    可以用for…of循环,for…of的循环可以避免开拓内存空间,增加代码运行效率:

    function test(first,...arg){
        for(let val of arg){
            console.log(val);
        }
    }
    test(1,2,3,4,5,6);

    2 ES6新增的数字操作

    2.1二进制声明(不是ES6特性)

    二进制的英文单词是Binary,二进制的开始是0(零),然后第二个位置是b(大小写都可以实现),然后跟上二进制的值就可以了。

    2.2八进制声明(不是ES6特性)

    八进制的英文单词是Octal,也是以0(零)开始的,然后第二个位置是O,然后跟上八进制的值就可以了。 

    例:

    //二进制声明
    let binary=0B010101;
    console.log('二进制binary:',binary);
    
    //八进制声明
    let octal=0O777;
    console.log('八进制octal:',octal);

    2.3数字验证

    可以用Number.isFinite( )进行数字验证,只要是数字,不论是浮点型还是整形都会返回true,其他时候会返回false

    console.log(Number.isFinite(888));
    console.log(Number.isFinite(11/4));
    console.log(Number.isFinite('abc'));
    console.log(Number.isFinite(NaN));
    console.log(Number.isFinite(undefined));

    2.4 NaN验证

    NaN是特殊的非数字,可以使用Number.isNaN()来进行验证

    console.log(Number.isNaN(0));
    console.log(Number.isNaN(NaN));

    2.5判断是否为整数

    Number.isInteger()
    console.log(Number.isInteger(100));
    console.log(Number.isInteger(99.99));

    2.6转换

    整数转换Number.parseInt()

    浮点型转换Number.parseFloat()

    let a='9.99';
    let b='aaa';
    console.log(Number.parseInt(a));
    console.log(Number.parseFloat(a));
    console.log(Number.parseInt(b));
    console.log(Number.parseFloat(b));

    2.7整数取值范围

    整数的操作是有一个取值范围的,就是-(253-1)到253-1。

    在计算时会经常超出这个值,所以要进行判断,ES6提供了两个常数,就不用去计算了,直接用就可以:

    //最大安全整数
    console.log(Number.MAX_SAFE_INTEGER);
    //最小安全整数
    console.log(Number.MIN_SAFE_INTEGER);

    安全整数判断:

    let c=Math.pow(2,53);
    let d=Math.pow(2,53)-1;
    console.log(Number.isSafeInteger(c));
    console.log(Number.isSafeInteger(d));

    3新增的数组知识

    3.1 JSON数组格式转换:Array.from()方法

    JSON的数组格式就是为了前端快速的把JSON转换成数组的一种格式

    例:

    let json={
        0:1,
        1:2,
        2:'abc',
        length:3
    }

    这就是一个标准的JSON数组格式(注意key值就是0,1,2...,不能随意起别的键名),跟普通的JSON对比是在最后多了一个length属性,没有length就只是字符串,有length才是数组。

    这种特殊的json格式可以使用ES6的语法转变成数组:

    let json={
        0:1,
        1:2,
        2:'abc',
        length:3
    }
    let arr=Array.from(json);
    console.log(arr);

    3.2 Array.of()方法

    可以把一堆文本或者变量转换成数组。(之前可以用eval来进行转换,但是eval的效率很低,会拖慢程序,所以尽量不要用)

    例:

    let arr=Array.of(1,2,3,4);
    console.log(arr);
    
    let arr2=Array.of('a','b','c');
    console.log(arr2);

    3.3 find()方法

    find()是一个实例方法,实例方法就是必须有一个已经存在的数组来调用,而前面两个方法是用Array对象直接调用的。

    (java中曾学过静态方法和实例方法,所以这里很好理解)

    find方法是从数组中查找,需要传入一个匿名函数,函数需要传入三个参数:

             value:表示当前查找的值。

             index:表示当前查找的数组索引。

             arr:表示当前数组。

    在函数中如果找到符合条件的数组元素就进行return,并停止查找。如果没有满足条件的,就返回undefinded。

    例1:

    let arr=[1,2,3,4,5];
    console.log(arr.find(function(val,index,arr){
        return val>3;
    }));

    例2:

    let arr1=['a','b','c'];
    console.log(arr1.find(function(val,index,arr){
        return val=='d';
    }));

    3.4 fill()方法

    fill()也是一个实例方法,它的作用是把数组进行填充,它接收三个参数,第一个参数是填充的变量,第二个是开始填充的位置,第三个是填充到的位置。

     

    例:

    let arr=[1,2,3,4,5];
    arr.fill('abc',2,4);
    console.log(arr);

    3.5数组的遍历

    1) for…of循环

    这种形式比ES5的for循环要简单而且高效,比普通for少声明一个i,这个i用完就没意义了。

    (for of就类似java中的增强for)

    例:

    let arr=[1,2,3,4,5];
    for(let item of arr){
        console.log(item);
    }

    输出数组索引:

    let arr=[1,2,3,4,5];
    for(let index of arr.keys()){
        console.log(index);
    }

    同时输出数组的内容和索引:

    let arr2=['你好','abc','12345'];
    for(let [index,item] of arr2.entries()){
        console.log(index+':'+item);
    }

    2)forEach

    forEach循环会自动省略为空的数组元素,相当于直接筛空了。

    let arr=['abc','123','Hello'];
    arr.forEach((val,index)=>console.log(index,val));

     

    (这里用了箭头函数,先用一下,后面会再详细写)

    3)filter

    let arr=['abc','123','Hello'];
    arr.filter(x=>console.log(x));

    4)some

    let arr=['abc','123','Hello'];
    arr.some(x=>console.log(x));

    5)map

    map起到一个替换的作用:

    let arr=['abc','123','Hello'];
    console.log(arr.map(x=>'替换后的值'));

    3.6数组转换字符串

    1)join()方法

    join()方法就是在数组元素中间,加了一些间隔,开发中很有用处。

    let arr=['abc','123','Hello','你好'];
    console.log(arr.join('-'));

    2)toString()方法

    转换时只是用逗号隔开了:

    let arr=['abc','123','Hello','你好'];
    console.log(arr.toString());

    3.7 entries()方法

    entries()生成的是Iterator形式的数组,这种形式的好处是可以在需要时用next()手动跳转到下一个值。Entries的意思是条目。 

    例:

    let arr=['abc','你好','学习es6'];
    let list=arr.entries();
    console.log(list);
    console.log(list.next().value);

    当想生成一些不规则的循环时,就可以用entries,这就叫手动循环。(上面的for of循环叫自动循环)

    例:

    let arr=['abc','你好','学习es6'];
    let list=arr.entries();
    console.log(list.next().value);
    console.log('---------------');
    console.log(list.next().value);
    console.log('***************');
    console.log(list.next().value);
    console.log('@@@@@@@@@@@@@@@');
    console.log(list.next().value);

    3.8 in的用法

    in是用来判断对象或者数组中是否存在某个值的。

    例:对象判断

    let obj={
        a:'你好',
        b:'你是谁'
    }
    console.log('a' in obj);
    console.log('你好' in obj);

    说明判断的是key值

    例:数组判断:

    以前会使用length属性进行判断,其存在弊端:

    let arr=[,,,];
    console.log(arr.length); 

    数组中其实全是空值,却输出了长度为3,这是不准确的。

    用ES6的in就可以解决这个问题:

    let arr=[,,,];
    console.log(0 in arr); 
    
    let arr2=[1,2,3,];
    console.log(0 in arr2);

    注意:这里的0指的是数组下标位置是否为空。

    4新增的函数知识

    4.1参数的默认值 

    function fun1(a,b=1){
        return a+b;
    }
    console.log(fun1(2));

    4.2主动抛出错误

    function fun2(a){
        if(a==1){
            throw new Error("这里报错了!");
        }
        return a+b;
    }
    console.log(fun2(1));

    4.3严谨模式

    之前严谨模式必须写在代码最上边,相当于全局使用,在ES6中可以写在函数体中,相当于针对函数来使用。

    例:

    function fun3(a,b=2){
        'use strict'
        return a+b;
    }
    console.log(fun3(1));

    说明使用了默认值,再使用严谨模式的话,就会有冲突。

    把默认值去掉:

    function fun3(a,b){
        'use strict'
        return a+b;
    }
    console.log(fun3(1,2));

    4.4获得需要传递的参数个数

    function fun4(a,b){
        return a+b;
    }
    console.log(fun4.length);

    如果加上默认值:

    function fun4(a,b=1){
        return a+b;
    }
    console.log(fun4.length);

    这说明length表示必须传入的参数个数。

    4.5对象的函数解构

    实际作用:后端经常返回来JSON格式的数据,直接把这个JSON格式数据当作参数,传递到函数内部进行处理。

    例:

    let json={
        a:'abc',
        b:'123'
    }
    function fun({a,b}){
        console.log(a,b);
    }
    fun(json);

    这样方便了很多,不用一个个传递参数了。

    4.6数组的函数解构

    let arr=['abc','123','哈哈'];
    function test(a,b,c){
        console.log(a,b,c);
    }
    test(...arr);

    4.7最后的参数可以带逗号

    之前是不能有,有了报错,现在没关系了

    function show(a,b,c,){
        console.log(a,b,c);
    }
    show(1,2,3,);

    这个在实际开发中会带来方便。

    4.8箭头函数

    箭头函数使用频率非常高,所以单独总结了:

    https://www.cnblogs.com/hzhjxx/p/12046043.html

    5 ES6中对象

    5.1对象赋值

    原来怎么赋值的:

    let name='小笼包';
    let age=18;
    
    let obj={
        name:name,
        age:age
    }
    console.log(obj);

    ES6允许把声明的变量直接赋值给对象。不用写key值了,直接把变量放进去,这样就大大简化了:

    let name='小笼包';
    let age=18;
    
    let obj={name,age}
    console.log(obj);

    5.2对象Key值构建

    有时候前台不知道key值的名称,是要从后台取的,这时可以用[ ] 的形式,进行对象的构建:

    let key='name';
    let obj={
        [key]:'前台定义的值'
    }
    console.log(obj);

    5.3 is()方法

    把两个对象进行比较。

    之前可以用===来比较:

    let obj1={name:'名字'};
    let obj2={name:'名字'};
    console.log(obj1.name===obj2.name);

    现在可以用is方法:

    let obj1={name:'名字'};
    let obj2={name:'名字'};
    console.log(Object.is(obj1.name,obj2.name));

     

    这两种比较的区别:

    ===为同值相等,is()为严格相等

    console.log(+0===-0);
    console.log(Object.is(+0,-0));

    console.log(NaN===NaN);
    console.log(Object.is(NaN,NaN));

    5.4 assign()合并对象

    let a={
        name:'名字'
    }
    let b={
        age:20
    }
    let c={
        like:'web'
    }
    let d=Object.assign(a,b,c);
    console.log(d);

    如果有重复的key值,后面的会覆盖前面的:

    let a={
        name:'名字'
    }
    let b={
        age:20,
        name:'名字2'
    }
    let c={
        like:'web',
        age:22,
    }
    let d=Object.assign(a,b,c);
    console.log(d);

    6 Symbol在对象中的应用

    6.1用Symbol构建对象的Key

    let sy=Symbol();
    let obj={
        [sy]:'sy的值'
    }
    console.log(obj[sy]);
    obj[sy]='新值';
    console.log(obj[sy]);

    6.2 Symbol对象元素的保护作用

    在对象中有很多值,但是循环输出时,并不希望全部输出,就可以使用Symbol进行保护

    let obj={
        name:'名字',
        like:'吃'    
    }
    let age=Symbol();
    obj[age]=18;
    console.log(obj);
    for(let item in obj){
        console.log(obj[item]);
    }

    可以看到,age被保护了。

    7 Set和WeakSet数据结构

    Set的定义和一些常用方法可以看这里:https://www.cnblogs.com/hzhjxx/p/11460420.html

    7.1set的遍历

    1)用for...of

    let setArr=new Set(['abc','Hello','123']);
    for(let item of setArr){
        console.log(item);
    }

    2)forEach:

    let setArr=new Set(['abc','Hello','123']);
    setArr.forEach((val)=>console.log(val));

    7.2 WeakSet

    注意不能直接在new 的时候放入值,会报错,要先把对象定义好,再用add方法添进去。

    let weakObj=new WeakSet();
    let obj={
        name:'大美女',
        age:'18'
    }
    weakObj.add(obj);
    console.log(weakObj);

    WeakSet里边的值不允许有重复的对象:

    let weakObj=new WeakSet();
    let obj={
        name:'大美女',
        age:'18'
    }
    let obj2={
        name:'大美女',
        age:'18'
    }
    weakObj.add(obj);
    weakObj.add(obj2);
    console.log(weakObj);

    因为obj和obj2不是同一个对象。

    如果是同一个:

    let weakObj=new WeakSet();
    let obj={
        name:'大美女',
        age:'18'
    }
    let obj2=obj;
    weakObj.add(obj);
    weakObj.add(obj2);
    console.log(weakObj);

    8 Map数据结构

    先看一个json对象的取值:

    let json={
        name:'大美女',
        age:18
    }
    console.log(json.name);

    这种方法其实是需要遍历整个对象进行寻找的,所以效率要比数组低。

    8.1声明Map

    let map=new Map();

    用set方法添加值:

    let json={
        name:'大美女',
        age:18
    }
    let map=new Map();
    map.set(json,'me');
    console.log(map);

    map的灵活性就在此,key值和value值可以没规律,可以是任意类型。

    8.2方法和属性

    let json={
        name:'大美女',
        age:18
    }
    let map=new Map();
    
    //添加值
    map.set(json,'me');
    map.set('me2',json);
    
    //长度
    console.log(map.size);
    
    //取值
    console.log(map.get(json));
    console.log(map.get('me2'));
    
    //查找
    console.log(map.has(json));
    
    //删除
    map.delete(json);
    console.log(map);
    
    //清空
    map.clear();
    console.log(map);

    Map应用广泛,因为他更灵活,更高效。

    9用Proxy进行预处理

    当操作一个对象或者方法时会有几种动作,例如在运行函数前初始化一些数据,在改变对象值后做一些善后处理。这些都算钩子函数。

    Proxy的存在就可以给函数加上这样的钩子函数,可以理解为在执行方法前预处理一些代码。也可以简单的理解为是函数或者对象的生命周期。

    Proxy的应用可以使函数更加强大,业务逻辑更加清楚,而且在编写自己的框架或者通用组件时非常好用。

    9.1声明Proxy

    new Proxy({},{});

    第一个花括号相当于方法的主体,后边的花括号就是Proxy代理处理区域,相当于写钩子函数的地方。

    9.2 get属性

    get属性是在得到某对象属性值时预处理的方法,它接收三个参数:

    target:得到的目标值

    key:目标的key值,相当于对象的属性

    property:这个不太常用

    9.3 set属性

    set属性是要改变Proxy属性值时,进行的预先处理。它接收四个参数:

    target:目标值。

    key:目标的Key值。

    value:要改变的值。

    receiver:改变前的原始值。

    例:

    let pro=new Proxy({
        add:function(val){
            return val+10;
        },
        name:'这是我的名字'
    },{
        get:function(target,key,property){
            console.log('运行get');
            return target[key];
        },
        set:function(target,key,value,receiver){
            console.log('运行set');
            return target[key]=value;
        }
    });
    console.log(pro.name);
    pro.name='新名字';
    console.log(pro.name);

    9.4 apply

    apply是对方法的预处理

    let target = function () {
        return 'Hello';
    };
    var handler = {
        apply(target, ctx, args) {
            console.log('apply运行了');
            return Reflect.apply(...arguments);
        }
    } 
    var pro = new Proxy(target, handler); 
    console.log(pro());

    10 promise对象的使用

    promise很好的解决了回调地狱的问题。

    ES5的时候,在多层嵌套回调时,代码层次过多,很难进行维护和二次开发。

    promise可以完美解决这个问题。

    promise这个单词是“承诺”,当它成功时执行一些代码,当它失败时执行一些代码。它更符合人类的行为思考习惯。

    promise执行多步操作非常好用。模仿一个多步操作的过程:

    let state=1;
    function step1(resolve,reject){
        console.log('第一步:做饭');
        if(state==1){
            resolve('做饭完成');
        }else{
            reject('做饭失败');
        }
    }
    function step2(resolve,reject){
        console.log('第二步:吃饭');
        if(state==1){
            resolve('吃饭完成');
        }else{
            reject('吃饭失败');
        }
    }
    function step3(resolve,reject){
        console.log('第三步:洗碗');
        if(state==1){
            resolve('洗碗完成');
        }else{
            reject('洗碗失败');
        }
    }
    
    new Promise(step1).
    then(function(val){
        console.log(val);
        return new Promise(step2);
    }).
    then(function(val){
        console.log(val);
        return new Promise(step3);
    }).
    then(function(val){
        console.log(val);
        return val
    });

    如果某一步出错:

    promise可以让代码更加的结构化。在现在的开发中使用率算是最高的。

    11 class类的使用

    11.1类的声明

    class Coder{
        name(val){
            console.log(val);
        }
    }
    let me=new Coder;
    me.name('你的名字');

    当有多个方法时:

    class Coder{
        name(val){        
            return val;
        }
        skill(val){
            console.log(this.name('张三')+'的技能是'+val);
        }
    }
    let me=new Coder;
    me.skill('web开发');

    注意方法和方法中间不要写逗号,this指类本身。

    11.2类的传参

    用constructor( )进行传参。传递参数后可以直接使用this.xxx进行调用。

    class Coder{    
        constructor(a,b){
            this.a=a;
            this.b=b;
        }
        add(){
            return this.a+this.b;
        }
    }
    let me=new Coder(1,2);
    console.log(me.add());

    11.3 class的继承

    class Coder{
        name(val){        
            console.log(val);
        }    
    }
    class Htmler extends Coder{
        
    }
    let me=new Htmler;
    me.name('我是一个切图人员');

    注意在写类的时候和ES5中的对象和构造函数要区分开,不要学混了。

    12模块化操作

    模块化操作主要包括两个方面:

    export:模块的输出。

    import:模块的引入。

    谷歌浏览器地址栏中输入:

    chrome://flags/,然后搜索javascript,把Experimental JavaScript设为启用:

     

    引入js文件时,要加上type="module"

    这样就可以直接预览效果了。

    12.1 export的用法

    export可以把变量,函数,对象进行模块化,提供外部调用接口,让外部进行引用。

    12.1.1把一个变量模块化

    temp.js:

    export var a='abc';

    index.js:

    import {a} from './temp.js';
    console.log(a);

    index.html:

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
            <title></title>
        </head>
        <body>
            <script type="module" src="index.js"></script>
        </body>
    </html>

    12.1.2多变量的输出

    temp.js:

    var a='aaa';
    var b='bbb';
    var c='ccc';
    
    export {a,b,c}

    index.js:

    import {a,b,c} from './temp.js';
    console.log(a,b,c);

    12.1.3函数的模块化输出

    temp.js:

    export function test(a,b){
        return a+b;
    }

    index.js:

    import {test} from './temp.js';
    console.log(test(10,20));

    12.1.4 as的用法

    有时候不想暴露模块里的变量名称,而给模块起一个更语义化的名称,可以使用as来操作。

    temp.js:

    var a='张三';
    var b=18;
    export {
        a as name,
        b as age
    }

    index.js:

    import {name,age} from './temp.js';
    console.log(name,age);

    12.2 export和export default的区别

    加上default相当于是一个默认的入口。在一个文件里export default只能有一个。

    例1:写两个export:

    temp.js:

    export var a ='aaa'; 
    export function add(a,b){
        return a+b;
    }

    index.js:

    import {a,add} from './temp.js';
    console.log(a,add(10,20));

    例2:export default

    export default var a=12345';
    import str from './temp';

    这时import可以不写{},而且可以自定义命名。

    (这里在chrome预览时报错,以后还是找个方式打包一下,等学完webpack再修改这里。)

    总结

    开发时尽量使用ES6语法,多用才熟练。如果生产环境不兼容,可以写完再用babel等工具转换。

  • 相关阅读:
    react路由,路由配置写在哪里?
    fastadmin中自建留言板的总结(一)TP5.0的数据流程
    精通JS的调试之控制台api大全,抓住数据的本质,本质!本质!!
    react中的,invoke,evoke,dispatch,assign都是什么意思,有什么区别
    leetcode——215.数组中的第k个最大的数
    leetcode——53.最大子序和
    leetcode——441.排列硬币
    leetcode——1137.第N个斐波那契数
    leetcode——70.爬楼梯
    leetcode——509.斐波那契数
  • 原文地址:https://www.cnblogs.com/hzhjxx/p/12076264.html
Copyright © 2020-2023  润新知