es6重要内容用法

ES6

一、ECMA历史

组成部分: ECMA、DOM、BOM

  1. 什么是ECMA?全称 ECMAScript 简写 ECMA 或 ES

    ECMA是一个标准,JS是实现

    例如: HTML5 是标准,chrome,FF,IE10是实现

    将来也可能有 xxxscript 实现ECMA

  2. 目前的版本:

    1. 低级浏览器: 主要支持es3.1,3.2
    2. 高级浏览器: 正从ES5过度到ES6
  3. 版本进化过程

    1996            ES1.0       js稳定    Netscape将js提交给ECMA组织
    1998            ES2.0       正式发布
    1999            ES3.0       浏览器广泛支持
    2007            ES4.0       ES4过于激进,被废除
    2008            ES3.1       4.0变为缩水版的3.1  代号:Harmony
    2009            ES5.0       ES5 正式发布,同时公布了javascript.next-6.0前身
    2011            ES5.1       成为ISO国际标准
    2013.3          ES6.0       ES6.0制定草案
    2013.12         ES6.0       发布草案
    2015.6          ES6.0       ES6.0预计发布,同时发布 es7.0正在制定草案
    
  4. 兼容性:

    目前为止ES5 ES6支持情况还凑合
    
    nodejs用的就是chrome内核,在node中已经可以使用es6的很多特性了
    
    ES5和ES6已经逐渐沦为后台语言
    

    1. 在浏览器中如何使用?需要编译工具,把ES6语法编译成ES5
        babel
        traceur     ---google出的编译器
        bootstrap   引导程序
        <script src="traceur.js"></script>
        <script src="bootstrap.js"></script>
        <script type="module">
            let a = 12;
        </script>


        <script src="https://traceur-compiler.googlecode.com/git/bin/traceur.js"
                type="text/javascript"></script>
        <script src="https://traceur-compiler.googlecode.com/git/src/bootstrap.js"
                type="text/javascript"></script>
        <script>
          traceur.options.experimental = true;
        </script>
        <script type="module" src="js/calc.js"></script>

    2. 在线编译:主要用于测试

        a. babeljs.io/repl
        b. google.github.io/traceur-compiler/demo/repl.html

    3. 在node中可以直接使用

        "use strict"
        let a = 12;
        console.log(a);

        a. 直接用,需要添加 use strict
        b. node --harmony_destructuring xx.js

二、定义变量 let和const

  1. ES6新增了let命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。

let定义的变量不能在相同作用域下,重复声明同一个变量

    function () {
        let a = 10;
        var a = 1;
    }

    function () {
        let a = 10;
        let a = 1;
    }

以下现象用来理解块级作用域

现象1:

    {
        let a = 10;
        var b = 1;
    }
    console.log(a);
    console.log(b);

结论:let声明的变量尽在 {}内有效

现象2: let声明的变量仅在当前作用域中有效

    for(let i=0;i<10;i++){}
    console.log(i);

现象3:

    var a = [];
    for (var i = 0; i < 10; i++) {
        a[i] = function () {
            console.log(i);
        };
    }
    a[6]();
    //========
    var a = [];
    for (let i = 0; i < 10; i++) {
        a[i] = function () {
            console.log(i);
        };
    }
    a[6]();
    i是let声明的,所以当前的 i仅在本轮循环有效,直接会被解析成数字。

现象4:循环语句是父作用域,循环体是一个独立的作用域,互不影响。

    for (let i = 0; i < 3; i++) {
        let i = 'abc';
        console.log(i);
    }

现象5: 不存在变量提升

    // var 的情况
    console.log(foo);
    var foo = 2;

    // let 的情况
    console.log(bar);
    let bar = 2;

现象6: 暂时性死区

    var tmp = 123;

    if (true) {
        tmp = 'abc'; // ReferenceError
        let tmp;
    }

报错:因为当使用let时,当前快作用域被封闭,let定义的变量仅能够在之后使用

为什么需要块级作用域?

  1. 内层变量可能会覆盖外层变量。

    var tmp = new Date();
    
    function f() {
        console.log(tmp);
        if (false) {
            var tmp = 'hello world';
        }
    }
    f();
    
  2. 用来计数的循环变量泄露为全局变量。

    var s = 'hello';
    for (var i = 0; i < s.length; i++) {
        console.log(s[i]);
    }
    console.log(i); // 5
    

块级作用域试题

1.

    function f1() {
        let n = 5;
        if (true) {
            let n = 10;
        }
        console.log(n); // 5
    }
  1. 自执行函数封闭作用域,可以用块作用域替代

    // IIFE 写法
    (function () {
        var tmp = ...;
        ...
    }());
    
    // 块级作用域写法
    {
        let tmp = ...;
        ...
    }
    

3.

    function f() { console.log('I am outside!'); }

    (function () {
          if (false) {
            // 重复声明一次函数f
            function f() { console.log('I am inside!'); }
          }

          f();
    }());

二、const 声明一个只读的常量。一旦声明,常量的值就不能改变

const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值。

  1. const的作用域与let命令相同:只在声明所在的块级作用域内有效。

    if (true) {
        const MAX = 5;
    }
    MAX
    

三、解构赋值

  1. 什么是解构赋值? 左边一种结构,右边一种结构,左右一一对应进行赋值

  2. 分类

  3. 数组解构赋值 **

  4. 对象解构赋值 **

  5. 字符串解构赋值

  6. 布尔值解构赋值

  7. 函数参数解构赋值

  8. 数值解构赋值

1 解构赋值基本方式

    let [x,y] = [1,2];
    console.log(x,y);//1,2

2 ...解构赋值

    {
        let a,b,rest;
        [a,b,...rest] = [1,2,3,4,5,6];
        console.log(a,b,rest);//rest [3,4,5,6]
    }

3 对象解构赋值

    //对象的解构赋值
    {
        let a,b;
        ({a,b} = {a:1,b:2});
        console.log(a,b);
    }

4 默认值(没有找到配对有默认值使用默认值,没有默认值值为 undefined)

    // 解构赋值的默认值
    {
        let a,b,c,rest;
        [a,b,c=3,d] = [1,2];
        console.log(a,b,c,d);
    }

5 变量交换

    //利用解构赋值交换变量中的值
    {
        let a = 1;
        let b = 2;
        [a,b] = [b,a];
        console.log(a,b);
    }

6 函数返回多个值

    function f(){
        return [1,2];
    }
    let [a,b] = f();
    console.log(a,b);

7 选择性的接收 返回值

    {
        function f(){
            return [5,6,7,8,9];
        }
        let [a,,,,b] = f();
        console.log(a,b);
    }

8 我只关心第一个,其他的先放数组里

    {
        function f(){
            return [5,6,7,8,9];
        }
        let [a,...b] = f();
        console.log(a,b);
    }

9 对象结构赋值

    {
        let o = {name:'yuonly',age:20};
        let {age,name} = o;
        console.log(name,age);
    }

10 可以替代 arguments

    // ... 可以替代arguments
    {
      function test3(...arg){
        for(let v of arg){
          console.log('rest',v);
        }
      }
      test3(1,2,3,4,'a');
    }

四、对象扩展

1. 简洁表示法

    //简洁表达
    {
        let a = 1;
        let b = 2;
        //ES5
        let es5 = {
            a:a,
            b:b
        }
        console.log(es5);
        //ES6
        let es6 = {
            a,
            b
        }
        console.log(es6);

    }
    {
        //如果有方法的处理方式
        // ES5
        let es5 = {
            hello:function(){
                console.log('hellow');
            }
        }
        //ES6
        let es6 = {
            hello(){
                console.log('hello');
            }
        }
    }

2. 属性表达式

    let a = 'b';
    let es5_obj = {//es5中对象的 key必须是固定的
        a:'c'
    }
    //es6
    let es6_obj = {//属性值可以是变量
        [a] : 'c'
    }
    console.log(es6_obj,'es6_obj');

3. 扩展运算符(ES7语法,支持不好,了解)

    {
        //babel不支持,无法编译
        let {a,b,...c} = {a:'test',b:'kill',c:'ddd',d:'ccc'}
        c = {
            c:'ddd',
            d:'ccc'
        }
    }

4. object新增API

    {
        // is :判断两个值是否相等
        console.log('字符串',Object.is('abc','abc'));
        console.log('数组',Object.is([],[]));//两个不同的地址

        //assign : 潜拷贝
        console.log('拷贝',Object.assign({a:'a'},{b:'b'}));

        // entries
        let test = [k:123,o:456];
        for(let [key,value] of Object.entries(test)){
            console.log([key,value]);
        }
    }

五、类

1 基本语法

    {
        //基本定义和生成实例
        class Person{
            constructor(name='laozhou'){
                this.name = name;
            }
        }
        let p1 = new Person('小王');
        console.log('构造函数和实例',p1);
    }

2 类的继承

    {
        //继承
        class Father{
            constructor(name='laozhou'){
                this.name = name;
            }
        }
        class Child extends Father{

        }
        console.log('子类的实例',new Child());
        console.log('子类自己传',new Child('小刘'))

    }


    {
        //子类如何覆盖父类的值
        class Father{
            constructor(name='laozhou'){
                this.name = name;
            }
        }
        class Child extends Father{
            constructor(name='child'){
                //this.type = 'boy';//super必须在第一行,否则报错
                super(name);//调用父亲类的构造函数
                this.type = 'boy';
            }
        }
        console.log('子类覆盖父类属性的实例',new Child());
    }

3 静态属性

    //静态属性
    {
        class Person{
            constructor(name='laozhou'){
                this.name = name;
            }
        }
        //静态属性的定义,是直接给类下的属性赋值,该属性就是静态属性
        Person.type = 'text';//type就是静态属性
    }

4 静态方法

    //静态方法
    {
        class Person{
            constructor(name='laozhou'){
                this.name = name;
            }
            static tell(){//相当于原型下的方法,是属于类本身的,用类来调用
                console.log('tell');
            }
        }
        Person.tell();
    }

5 getter-setter

    {
        //getter   setter
        class Father{
            constructor(name='laozhou'){
                this.name = name;
            }
            //此处longName不是函数而是属性,相当于新增了一个属性 longName
            get longName(){
                return 'yu_'+this.name;
            }
            set longName(value){
                this.name = value;
            }
        }

        let f1 = new Father();
        console.log('getter',f1.longName);
        f1.longName = 'hello';
        console.log('setter',f1.longName);
    }

六、promise

promise是异步变成的解决方案(解决回调地狱)

1 基本写法

    {
        //es5 中的异步操作
        let ajax = function(callback){
            console.log('执行');
            setTimeout(function(){
                callback && callback.call();
            },1000);
        }
        ajax(function(){
            console.log('timeout1');
        })
    }

    {
        //ES6
        let ajax = function(){
            console.log('执行2');
            return new Promise(function(resolve,reject){
                setTimeout(function(){
                    resolve();//resolve后会有then方法,执行后续操作
                },1000);
            })
        }
        ajax().then(function(){
            console.log('promise','timeout');
        })
    }

2 promise.all 所有的 异步操作都成功后,在去执行一个动作。例子,图片都加在完成之后再显示到页面

    //promise.all :把多个promise实例当做一个promise实例,当所有的状态都完成之后,才会触发新的promise对象的then方法

    //应用,比如广告中有三张图,需要三张图都加载再去更新dom
    {
        //所有图片加载完成在加载页面
        function loadImg(src){
            return new Promise((resolve,reject)=>{
                let img = document.createElement('img');
                img.src = src;
                img.onload = function(){
                    resolve(img);
                }
                img.onerror = function(){
                    reject(err);
                }
            })
        }

        function showImg(imgs){
            imgs.forEach(function(img){
                document.body.appendChild(img);
            })
        }

        Promise.all([
            loadImg('https://img10.360buyimg.com/n4/s260x260_jfs/t3079/363/6070979658/42126/5b5c2f39/589af086N4a3bed39.jpg'),
            loadImg('https://img14.360buyimg.com/n4/s260x260_jfs/t4345/284/2534342556/119746/550dee37/58d34a9dNf0bd717f.jpg'),
            loadImg('https://img13.360buyimg.com/n4/s260x260_jfs/t3259/170/5587914266/144572/64259fc5/5873347aN14e34822.jpg'),
        ]).then(showImg);

    }

3 promise.race 谁先到加载谁

    {
        //promise.race  谁先回来处理谁,先到先得
        function loadImg(src){
            return new Promise((resolve,reject)=>{
                let img = document.createElement('img');
                img.src = src;
                img.onload = function(){
                    resolve(img);
                }
                img.onerror = function(){
                    reject(err);
                }
            })
        }

        function showImgs(img){
            let p = document.createElement('p');
            p.appendChild(img);
            document.body.appendChild(p);
        }

        Promise.race([
            loadImg('https://img10.360buyimg.com/imgzone/jfs/t5149/215/1247256617/226900/c371168/590dcc2bN2234f761.jpg'),
            loadImg('https://img14.360buyimg.com/n4/s260x260_jfs/t4345/284/2534342556/119746/550dee37/58d34a9dNf0bd717f.jpg'),
            loadImg('https://img13.360buyimg.com/n4/s260x260_jfs/t3259/170/5587914266/144572/64259fc5/5873347aN14e34822.jpg'),
        ]).then(showImgs);
    }

4 promise可以让代码执行的步骤更清晰,过程更可控

    //使用promise后,更清晰
    {
        let oBox = document.getElementById('box');

        function toWidth(w){
            return new Promise(function(resolve,reject){
                let timer = setInterval(function(){
                    var oldWidth = oBox.clientWidth;
                    if(oldWidth>w){
                        clearInterval(timer);
                        resolve();
                    }
                    oBox.style.width = oldWidth + 10 + 'px';
                },100);
            })
        }

        function toHeight(h){
            return new Promise(function(resolve,reject){
                let timer = setInterval(function(){
                    var oldHeight = oBox.clientHeight;
                    if(oldHeight>h){
                        clearInterval(timer);
                        resolve();
                    }
                    oBox.style.height = oldHeight + 10 + 'px';
                },100);
            })
        }

        function toSmall(size){
            return new Promise(function(resolve,reject){
                let timer = setInterval(function(){
                    var oldWidth = oBox.clientWidth;
                    var oldHeight = oBox.clientHeight;
                    if(oldWidth<size || oldHeight<size){
                        clearInterval(timer);
                        resolve();
                    }
                    console.log(123);
                    oBox.style.width = oldWidth - 10 + 'px';
                    oBox.style.height = oldHeight - 10 + 'px';
                },100);
            })
        }

        //使用promise后,更清晰,可以随意更改流程。
        toHeight(400)
            .then(function(){
                return toWidth(600);
            })
            .then(function(){
                return toHeight(300);
            })
            .then(function(){
                return toSmall(100);
            })
            .then(function(){
                return toHeight(400);
            })
    }

    //ES5
    {
        function toWidth(w,callback){
            let timer = setInterval(function(){
                var oldWidth = oBox.clientWidth;
                if(oldWidth>w){
                    clearInterval(timer);
                    callback && callback();
                }
                oBox.style.width = oldWidth + 10 + 'px';
            },100);
        }

        function toHeight(h,callback){
            let timer = setInterval(function(){
                var oldHeight = oBox.clientHeight;
                if(oldHeight>h){
                    clearInterval(timer);
                    callback && callback();
                }
                oBox.style.height = oldHeight + 10 + 'px';
            },100);
        }

        function toSmall(size,callback){
            let timer = setInterval(function(){
                var oldHeight = oBox.clientHeight;
                var oldWidth = oBox.clientWidth;
                if(oldHeight<size){
                    clearInterval(timer);
                    callback && callback();
                }
                oBox.style.width = oldWidth - 10 + 'px';
                oBox.style.height = oldHeight - 10 + 'px';
            },100);
        }

        //代码可读性差,而且很难控制执行顺序
        toWidth(500,function(){
            toHeight(300,function(){
                toSmall(100,function(){
                    toWidth(400,function(){
                        toHeight(100,function(){

                        })
                    })
                });
            })
        });
    }

七、模块化

1. 基本概念:每一个文件都是独立的作用域,一个模块,都是独立存在,不会互相影响

2. ES6模块化语法

方式一: 优点:可以只导出部分模块。弊端,导出模块特别多的时候,不能一眼看出都导出了那些模块
    //模块的导出 module1.js
    export let a = 123;
    export function test(){
        console.log('test');
    }
    export class Hello{
        test(){
            console.log('class');
        }
    }
    //模块的导入 entry.js
    a as A 起别名 A,外部使用A来操作a
    import {a as A,test,Hello} from './lesson/6.module/module1.js';

    console.log(A,test,Hello);

    //导入所有模块放入 obj对象下
    import * as obj from './lesson/6.module/module1.js';
    console.log(obj.a);
方式二:推荐方式
    //导出 module2.js
    let num = 123;
    let test = function(){
        console.log('test');
    }
    class Person{
        test(){
            console.log('Person');
        }
    }
    //1,批量导出,一目了然导出了那些东西给外部 2, 没有起名字,将命名权给倒入方。
    export default {
        num,
        test,
        Person
    }


    //导入  entry.js
    import M from './lesson/6.module/module2.js';
    console.log(M,M.num);
    M.test()

八、函数扩展(箭头函数)

  • 参数默认值
  • rest参数
  • 扩展运算符(rest参数的逆运用)
  • 箭头函数
  • 尾调用

1 参数默认值

    {
        function test(x,y=10){
            console.log('默认值',x,y);
        }
        test(1);
        test(99,88);
    }
    // 有默认值的参数后面,不能有 没有默认值的参数
    {
        function test(x,y=10,c){//会报错,在默认值后面不能有 没有默认值的参数
            console.log('默认值',x,y);
        }
    }
    //函数的作用域
    {
        let x = 'test';
        function test2(x,x=y){
            console.log('作用域——',x,y);
        }
        test2('new');
    }
    //没有的时候用上面的
    {
        let x = 'test';
        function test2(c,y=x){
            console.log('作用域2',x,y);
        }
        test2('new');
    }

2 rest参数

    {
        //此时的arg相当于是 arguments
        function test3(...arg){
            for(let v of arg){
                console.log('rest:',v);
            }
        }
        test3(1,2,3,4,5);
    }

3 扩展运算符(rest参数的逆运用)

    {
        console.log(...[1,2,3]);
    }

4 箭头函数

    {
        let arrow = v=>v*10;
        console.log(arrow(3));

        <!-- let arrow2 = (v)=>{return v*50};
        console.log(arrow2(2)); -->
    }
    相当于是
    {
        let arrow = function(v){
            return v*10;
        }
        console.log(arrow(3));
    }

5 尾调用 :函数的最后一句话是函数,就是为调用

    {
        function tail(x){
            console.log('tail',x);
        }
        function go(x){
            return tail(x);
        }
        go(123);
    }
posted @ 2017-06-27 08:58  仇枫empress  阅读(186)  评论(0编辑  收藏  举报