• ECMAScript 6 | 新特性


    新特性概览

    参考文章: http://www.cnblogs.com/Wayou/p/es6_new_features.html

    —————————————————————————————————————————————————————————

    ES6测试引入文件

    <<bootstrap.js>>

    <<traceur.js>>

    —————————————————————————————————————————————————————————

    let命令

    • let命令用来声明变量,用法类似于var,但仅仅可以使用在定义的代码块中
    • 不存在变量提升
    • 暂时性死区:只要块级作用域内存在let命令,它所声明的变量就"绑定"binding这个区域,不再受外部影响
    • 不允许重复声明:let不允许在相同作用域内重复声明同一个变量

    样例

    <<test.js>>

    // 在该代码块中声明let,外部不能调用,花括号之内
    {
        let a = 100;
        var b = 200;
    }
    
    // console.log(a);
    // 在这里var进行了变量提升,可以在全局中使用,let不可以变量提升
    console.log(b);
    // ********************************************************************
    // 不存在变量提升
    // ES5
    var arr = [],
        arrTest = [];
    // 在循环中c并没有赋给数组,而是被i循环覆盖为9,所以输出的都是9
    for (var i = 0; i < 10; i++) {
        var c = i;
        arr[i] = function() {
            return c;
        }
    }
    // 遍历执行
    for (var i = 0; i < 10; i++) {
        arrTest[i] = arr[i]();
    }
    console.log(arrTest);
    
    // ES6
    var arr2 = [];
    // var c → let d
    for (var i = 0; i < 10; i++) {
        let d = i;
        arr2[i] = function() {
            return d;
        }
    }
    for (var i = 0; i < 10; i++) {
        arrTest[i] = arr2[i]();
    }
    console.log(arrTest);
    // 教学视频中没有说清楚,那么是否是因为let d 只对对应的代码块起作用,出现了10个不同的d呢?
    // ********************************************************************
    // 暂时性死区
    {
        console.log(e);
        let e = 100;
        console.log(e);
    }
    // 在视频中得到的结果是undefined和100,而在我的测试中第一个console.log得到的是报错信息,提示未定义
    // 在该代码块中let管辖着e,当未声明变量e时,打印e则会提示未定义的,暂时不可以使用的
    // ********************************************************************
    // 不允许重复声明
    {
        var f = 1;
        let f = 100;
    }
    {
        let g = 100;
        var g = 1;
    }
    // 重复声明会产生报错信息Identifier 'f' has already been declared

    <<index.html>>

    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="utf-8">
        <script src="traceur.js"></script>
        <script src="bootstrap.js"></script>
        <script type="text/javascript" src="test.js"></script>
    </head>
    
    <body>
    </body>
    
    </html>

    —————————————————————————————————————————————————————————

    块级作用域

    let实际上为JavaScript新增了块级作用域

    • ES5中只有全局作用域和函数作用域,没有块级作用域,容易出现以下问题:
      • 内层变量可能会覆盖外层变量
      • 用来计数的循环变量泄露为全局变量

    <<index.html>>

    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="utf-8">
        <script src="traceur.js"></script>
        <script src="bootstrap.js"></script>
        <!-- ES5 -->
        <script type="text/javascript">
        var time = new Date();
    
        function f1() {
            console.log(time);
            if (false) {
                var time = 'hello'; // 变量重复声明了之后,内部time会覆盖已有变量的内存地址,在运行时console.log会寻找地址,此时地址还没有存入值'hello',所以输出为undefined
                // time ='hello'; // 如果是使用赋值语句,则正常输出time为Date();
            }
        }
        f1();
        // ****************************************
        // 循环变量泄露为全局变量的问题
        for (var i = 0; i < 12; i++) {}
        // i跳出了循环体,循环结束后i没有被销毁
        console.log(i);
    
        // 在其他函数中也会被使用
        function f2() {
            console.log(i);
        }
        f2();
        // ****************************************
        // Demo1:
        // 第二次声明nTest1会覆盖第一次声明,得到200的值
        function f3() {
            var nTest1 = 100;
            if (true) {
                var nTest1 = 200;
            }
            console.log(nTest1);
        }
        f3();
        // ****************************************
        // Demo2:自调用函数
        // 视频演示中ES5得到的是inside,ES6得到的是outside
        // 测试时ES5报错,ES6正常inside
        function fun(){
            console.log('i am outside');
        };
        (function (){
            if (false) {
                function fun(){
                    console.log("i am inside");
                };
            }
            fun();
        })();
        </script>
        <!-- ES6 -->
        <script type="text/traceur">
        // ****************************************
        // Demo1:
            function f4() {
                let nTest2 = 100;
                if (true) {
                    let nTest2 = 200;
                    console.log(nTest2);
                }
                console.log(nTest2);
            }
            f4();
        // ****************************************
        // Demo2:自调用函数
        function fun(){
            console.log('i am outside');
        }
        (function (){
            if (false) {
                function fun(){
                    console.log("i am inside");
                }
            }
            fun();
        }())
        </script>
    </head>
    
    <body>
    </body>
    
    </html>

    —————————————————————————————————————————————————————————

    const命令

    const关键字声明的是常量,不可改变

    <<index.html>>

    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="utf-8">
        <script src="traceur.js"></script>
        <script src="bootstrap.js"></script>
        <!-- ES5 -->
        <script type="text/javascript">
            // const命令
            const Pi = 3.1415;
            console.log(Pi);
            // 赋值的话返回错误信息Assignment to constant variable.
            // Pi = 1;
            // ***********************************************************
            // const的块级作用域问题
            if (true) {
                var a = 1;
            }
            // Error: a is not defined
            // 可见const关键字定义的也有块级作用域的问题
            // console.log(a);
        </script>
        <!-- ES6 -->
        <script type="text/traceur">
            // 暂时性死区
            if (true) {
                console.log(b);
                const b = 2;
            }
            // ***********************************************************
            {
                //Error:["file:///F:/6.Code/Front-End/JavaScript/Test/index_inline_script_1.js:6:16: Duplicate declaration, c"]
                //不可重复声明
                //var c=200;
                const c = 300;
                console.log(c);
            }
            // ***********************************************************
            // 通过const声明对象时,显示这个对象是只读的,该对象是冻结状态的,但仍然可以写入值
            const person = {};
            person.name = "hello";
            console.log(person);
            person.name = "hugh";
            console.log(person);
            console.log(Object.isSealed());
            console.log(Object.isFrozen());
            // 如果以冻结方法定义的对象,则是无法写入的
            const person2 = Object.freeze({});
            person2.name = "hugh";
            person2.age = 21;
            console.log(person2);
            console.log(person2.name);
            console.log(person2.age);
            console.log(Object.isFrozen());
            // 正确的const冻结对象的方法
            const person3 = Object.freeze({
                name: 'hhh',
                age: 1
            });
            console.log(person3);
            console.log(Object.isFrozen());
            // ***********************************************************
            // const声明的数组可以数组操作,但不可以整体赋值,视为重新定义
            const arr1 = [];
            arr1.push(1);
            arr1.push(2);
            console.log(arr1);
            arr1.pop();
            console.log(arr1);
            console.log(arr1.length);
            //Error:["file:///F:/6.Code/Front-End/JavaScript/Test/index_inline_script_1.js:30:5: arr1 is read-only"]
            //arr1 = ['a','b','c'];
            //console.log(arr1);
            // ***********************************************************
            // 彻底冻结对象,请对比参考JavaScript中的递归冻结函数方法
            var constantize = (obj) => {
                Object.freeze(obj);
                Object.keys(obj).forEach((key,value)=>{
                    if(typeof obj[key]==='object'{
                        constantize(obj[key]);
                    });
                });
            };
        </script>
    </head>
    
    <body>
    </body>
    
    </html>

    —————————————————————————————————————————————————————————

    跨模块常量

    <<index.html>>

    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="utf-8">
        <script src="traceur.js"></script>
        <script src="bootstrap.js"></script>
        <!-- ES5 -->
        <script type="text/javascript">
    
        </script>
        <!-- ES6 -->
        <script type="text/traceur">
        // module.js, 在这里将变量输出
        export const cVariantName = "111";
        export const iVariantName = 3;
        export const fVariantName = 4.111;
    
        // use.js, 在这里将变量全部引入
        import * as variant from './module.js';
        console.log(variant.cVariantName); // 输出"111";
        console.log(variant.iVariantName); // 输出3;
        console.log(variant.fVariantName); // 输出4.111;
    
        // otherUse.js, 引入部分变量
        import {iVariantName,fVariantName} as variant from './module.js';
        console.log(variant.iVariantName); // 输出3;
        console.log(variant.fVariantName); // 输出4.111;
    
        // onlyUse.js, 只引入一个变量
        import iVariantName as variant from './module.js';
        console.log(variant.iVariantName); // 输出3;
        </script>
    </head>
    
    <body>
    </body>
    
    </html>

    —————————————————————————————————————————————————————————

    全局对象属性

    • 全局变量是最顶层的对象
    • 浏览器环境指的是window对象
    • Node.js指的是global对象
    • JavaScript中所有全局变量都是全局对象的属性

      p.s.Node中这一条只对REPL环境使用,模块环境必须显式声明成global属性

    • ES6规定:
      • varfunction命令声明的全局变量,属于全局对象的属性
      • letconstclass命令声明的全局变量,不属于全局对象的属性

    <<index.html>>

    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="utf-8">
        <script src="traceur.js"></script>
        <script src="bootstrap.js"></script>
        <!-- ES5 -->
        <script type="text/javascript">
    
        </script>
        <!-- ES6 -->
        <script type="text/traceur">
        var varName = "varValue";
        // 浏览器环境
        console.log(window.varName); // 输出varValue
        // Node环境
        // console.log(global.varName);
        // 通用环境
        console.log(this.varName); // 输出varValue
    
        let letName = "letValue";
        console.log(window.letName); // 兼容模式:letValue, 严格模式:undefined
        console.log(this.letName); // 兼容模式:letValue, 严格模式:undefined
        </script>
    </head>
    
    <body>
    </body>
    
    </html>

    —————————————————————————————————————————————————————————

    解构赋值 Dustructuring

    • 解构:ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值
    • 不完全解构:等号左边的模式只匹配一部分等号右边的数组
    • 指定默认值:ES6内部使用严格相等运算符===来判断一个位置是否有值,如果数组成员不严格等于undefined默认值不会生效
    • letconst命令:只要某种数据结构具有iterator(迭代器)接口,都可以采用数组形式解构赋值

    数组解构赋值

    <<index.html>>

    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="utf-8">
        <script src="traceur.js"></script>
        <script src="bootstrap.js"></script>
        <!-- ES5 -->
        <script type="text/javascript">
        // Set对象
        var s = new Set();
        s.add("Thomas Jefferson");
        s.add(1776);
        s.add("founding father");
    
        s.forEach(function (item) {
            console.log(item.toString() + ", ");
        });
    
        </script>
        <!-- ES6 -->
        <script type="text/traceur">
        //数组解构
        // 通过这种形式批量结构赋值
        var [a,b,c] = [1,2,3];
        console.log(a);
        console.log(b);
        console.log(c);
        // 对应位置数组解构
        let [foo,[[bar],,base]] = [1,[[2],3,4]];
        console.log(foo);
        console.log(bar);
        console.log(base);
        // ...tail 作为数组
        let [head, ...tail] = [0,1,2,3,4,5,6,7,8,9];
        console.log(head);
        console.log(tail);
        // 不完全解构
        let [x,y] = [1,2,3];
        console.log(x);
        console.log(y);
        let [x1,y1] = [100];
        console.log(x1); // 100
        console.log(y1); // undefined
        // 指定默认值
        var [temp = 'string'] = []; // 在这里temp的默认值为string,如果不给值的话为默认string
        console.log(temp);
        var [temp1 = 'string1'] = ['string2'];
        console.log(temp1);
        var [temp2 = 'aaa',temp3] = ['bbb']; 
        console.log(temp2); // 'bbb'
        console.log(temp3); // undefined, 解构时完全对应给定值,bbb赋值给temp2,没有值给tmep3,参见不完全解构
        var [temp4 = 'aaa'] = [undefined];
        console.log(temp4); // 'aaa' 因为给定的值是未定义的
        // 非遍历结构 - 报错
        // var [temp5] = 1; // traceur.js:31513 TypeError: 1[Symbol.iterator] is not a function
    
        // 迭代器
        let [a1,b1,c1] = new Set(['aaa','bbb','ccc']);
        console.log(a1);
        console.log(b1);
        console.log(c1);
        function* fibs(){
            let a2 = 0;
            let b2 = 1;
            while(true){
                yield a2;
                [a2,b2] = [b2,a2+b2];
            }
        }
        var [first,second,third,fourth,fifth,sixth] = fibs();
        console.log(first);
        console.log(second);
        console.log(third);
        console.log(fourth);
        console.log(fifth);
        console.log(sixth);
        </script>
    </head>
    
    <body>
    </body>
    
    </html>

    对象解构赋值

    <<index.html>>

    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="utf-8">
        <script src="traceur.js"></script>
        <script src="bootstrap.js"></script>
        <!-- ES5 -->
        <script type="text/javascript">
    
        </script>
        <!-- ES6 -->
        <script type="text/traceur">
        // 对象解构赋值
        var {name,age,id} = {id:'0001',name:'hugh',age:20};
        console.log(name);
        console.log(age);
        console.log(id); // 可以不按顺序
        // 变量名和属性名不一致
        var {change_name,age,id} = {id:'0001',name:'hugh',age:20};
        console.log(change_name); // undefined
        // 将变量名和属性名对应起来
        var {name:person_name,age:person_age,id:person_id} = {id:'0001',name:'hugh',age:20};
        console.log(person_id);
        console.log(person_name);
        console.log(person_age);
        // 重构对象
        let object = {first:1,second:2};
        let {first:first_num , second:second_num} = object; // 结构对象
        console.log(first_num);
        console.log(second_num);
        // 指定默认值
        // 结构默认值的条件为 === undefined
        var {x = 3,y = 5} = {};
        console.log(x);
        console.log(y);
        var {massage:msg = "yes!"} = {};
        console.log(msg);
        // 已声明变量的解构赋值
        var test;
        // {test} = {test:1};
        ({test} = {test:1});
        console.log(test);
        // 现有对象的方法
        let {sin,cos,tan} = Math;
        console.log(sin(Math.PI/6));
    
        </script>
    </head>
    
    <body>
    </body>
    
    </html>

    字符串解构赋值

    <<index.html>>

    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="utf-8">
        <script src="traceur.js"></script>
        <script src="bootstrap.js"></script>
        <!-- ES5 -->
        <script type="text/javascript">
    
        </script>
        <!-- ES6 -->
        <script type="text/traceur">
        // 字符串的解构赋值
        const [a,b,c,d,e,f] = "hello!"; // 逐位对应解构赋值
        console.log(a);
        console.log(b);
        console.log(c);
        console.log(d);
        console.log(e);
        console.log(f);
        // 字符串的length属性解构
        const {length : len} = "hhh"; // 通过对象取属性
        console.log(len);
        const {length} = "1111";
        console.log(length);
        </script>
    </head>
    
    <body>
    </body>
    
    </html>

    函数参数解构赋值

    <<index.html>>

    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="utf-8">
        <script src="traceur.js"></script>
        <script src="bootstrap.js"></script>
        <!-- ES5 -->
        <script type="text/javascript">
    
        </script>
        <!-- ES6 -->
        <script type="text/traceur">
        // 函数参数的解构赋值
        function sum ([x, y]){
            return x + y;
        }
        console.log(sum([1, 2])); // 解构赋值传入一个数组,数组变量解构赋值
    
        // 函数参数解构默认值
        // 在这里0和1并不是赋值操作,而是声明变量,所以不能使用以下这种方法:function fun({x, y} = {x : 0, y : 1}),将{x, y} = {x : 0, y : 1}作为函数内部的语句来操作,如果传入的是fun(),return 0 0,传入fun({x:100}),return 100 undefined
        function fun({x = 0, y = 1} = {}){ 
            return [x, y];
        }
        console.log(fun({x : 100})); // y返回的是默认值
        console.log(fun()); // x,y均返回默认值
        </script>
    </head>
    
    <body>
    </body>
    
    </html>

    解构赋值用途

    • 交换变量的值
    • 从函数返回多个值
    • 函数参数的定义
    • 提取Json数据
    • 函数参数的默认值
    • 遍历Map结构
    • 输入模块的指定方法

    <<index.html>>

    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="utf-8">
        <script src="traceur.js"></script>
        <script src="bootstrap.js"></script>
        <!-- ES5 -->
        <script type="text/javascript">
    
        </script>
        <!-- ES6 -->
        <script type="text/traceur">
        // 交换变量的值
        // ES5中通过temp变量, temp = a; a = b; b = temp;
        var x = 100, y = 200;
        [x, y] = [y, x];
        console.log([x, y]);
    
        // ************************************************************************************
        // 从函数返回多个值,优势:不需要使用fun.id之类的操作,直接取值到变量
        // 返回一个数组
        function fun(){
            return [1, 2, 3];
        }
        var [x, y, z] = fun();
        console.log(x);
        console.log(y);
        console.log(z);
        // 返回一个对象
        function fun1(){
            return {
                id : "0001",
                name : "hugh",
                age : 20
            };
        }
        var {id : person_id, name : person_name, age : person_age} = fun1();
        console.log(person_id);
        console.log(person_name);
        console.log(person_age);
    
        // ************************************************************************************
        // 函数参数的定义
        // 参数有次序
        function fun2([x, y, z]){
            console.log(x);
            console.log(y);
            console.log(z);
        }
        fun2([1, 2, 3]);
        // 参数无次序
        // 使用到的是对象的解构赋值,用于接口的交互,如果是使用AJAX交互时,没必要在传值前打包,直接封装成Json对象,打包好传过来,可以使整个模块更清晰
        function fun3({id, name, age}){
            console.log(id);
            console.log(name);
            console.log(age);
        }
        fun3({name : "dong", id : '0002', age : 30});
    
        // ************************************************************************************
        // 提取Json数据
        var jsonData = {
            id : "0003",
            name : "dong",
            age : 21,
            score : {
                Chinese : 99,
                Math : 98,
                English : 97
            }
        };
        // 通常情况下提取Json数据
        console.log(jsonData);
        console.log("id:"+jsonData.id);
        console.log("name:"+jsonData.name);
        console.log("chinese score:"+jsonData.score.Chinese);
        console.log("english score:"+jsonData.score.English);
        // ES6下解构后
        let {id:number, xingming, age, score:chengji} = jsonData;
        console.log("ES6:"+number);
        console.log("ES6:"+xingming);
        console.log("ES6:"+age);
        console.log("ES6:"+chengji.Chinese);
    
        // ************************************************************************************
        // 函数参数的默认值
        // 内建的ajax
        // jQuery.ajax({
        //     url :'/path/to/file',
        //     type :'POST',
        //     dataType : 'xml/html/script/json/jsonp',
        //     data : {param1 : 'value1'},
        //     complate : function(xhr, textStatus){
        //         // called when complete
        //     },
        //     success : function(data, textStatus, xhr){
        //         // called when success
        //     },
        //     error : function(xhr, textStatus, errorThrown){
        //         // called when there is an error  
        //     }
        // });
        // 解构赋值方式,通过参数的默认值来进行ajax运算,突出函数的传值
        // 避免了在函数体内部再写 var foo = config.foo || 'default foo'; 这样的语句
        // jQuery.ajax = function (url, {
        //     async = true,
        //     beforeSend = function (){},
        //     cache = true,
        //     complete = function (){},
        //     crossDomain = false,
        //     global = true,
        //     // ...more config
        // }){
        //     // ...do stuff
        // };
    
        // ************************************************************************************
        // 遍历Map解构
        var map = new Map();
        map.set("id","0007"); // 创建键值对
        map.set("name","hehe");
        console.log(map); // map结构是object
        for(let [key, value] of map){ // 遍历获取键值对
            console.log(key + " is " + value);
        }
        for (let[key] of map){ // 遍历获取键名
            console.log(key);
        }
        for (let [, value] of map){ // 遍历获取键值, p.s. [ , value] !!!
            console.log(value);
        } 
    
        // ************************************************************************************
        // 输入模块的指定方法
        const { SourceMapConsumer , SourceNode } = require("source-map");
        </script>
    </head>
    
    <body>
    </body>
    
    </html>

  • 相关阅读:
    【转载】基于TINY4412的Andorid开发-------简单的LED灯控制
    【Android 多媒体应用】使用MediaCodec将摄像头采集的视频编码为h264
    【Android 多媒体应用】使用MediaCodec解码使用SurfaceView显示视频
    【Android 多媒体应用】使用MediaCodec解码使用AudioTrack播放音频数据
    【Android 多媒体应用】使用 TTS
    【Android 多媒体应用】使用 VideoView 播放视频
    【Android 多媒体应用】使用 MediaPlayer 播放视频
    【Android 多媒体应用】使用MediaRecoder录制,MediaPlayer播放音频数据
    Android Binder 系统学习笔记(一)Binder系统的基本使用方法
    【转】Android下面打印进程函数调用堆栈(dump backtrace)的方法
  • 原文地址:https://www.cnblogs.com/hughdong/p/7249667.html
Copyright © 2020-2023  润新知