ECMAScript 6十大特性

ES6入门 http://es6.ruanyifeng.com/javascript

ES6排名前十的最佳特性列表html

  1. Default Parameters(默认参数) in ES6java

  2. Template Literals (模板文本)in ES6node

  3. Multi-line Strings (多行字符串)in ES6jquery

  4. Destructuring Assignment (解构赋值)in ES6webpack

  5. Enhanced Object Literals (加强的对象文本)in ES6git

  6. Arrow Functions (箭头函数)in ES6es6

  7. Promises in ES6github

  8. Block-Scoped Constructs Let and Const(块做用域构造Let and Const)web

  9. Classes(类) in ES6

  10. Modules(模块) in ES6

    1.Default Parameters(默认参数) in ES6

    还记得咱们之前不得不经过下面方式来定义默认参数:

    ?
    1
    2
    3
    4
    5
    6
    var  link =  function  (height, color, url) {
         var  height = height || 50;
         var  color = color ||  'red' ;
         var  url = url ||  'http://azat.co' ;
         ...
    }

    一切工做都是正常的,直到参数值是0后,就有问题了,由于在JavaScript中,0表示fasly,它是默认被hard-coded的值,而不 能变成参数自己的值。固然,若是你非要用0做为值,咱们能够忽略这一缺陷而且使用逻辑OR就好了!但在ES6,咱们能够直接把默认值放在函数申明里:

    ?
    1
    2
    3
    var  link =  function (height = 50, color =  'red' , url =  'http://azat.co' ) {
       ...
    }

    顺便说一句,这个语法相似于Ruby!

    2.Template Literals(模板对象) in ES6

    在其它语言中,使用模板和插入值是在字符串里面输出变量的一种方式。所以,在ES5,咱们能够这样组合一个字符串:

    ?
    1
    2
    var  name =  'Your name is '  + first +  ' '  + last +  '.' ;
    var  url =  'http://localhost:3000/api/messages/'  + id;

    幸运的是,在ES6中,咱们可使用新的语法$ {NAME},并把它放在反引号里:

    ?
    1
    2
    var  name = `Your name is ${first} ${last}. `;
    var  url = `http: //localhost:3000/api/messages/${id}`;

    3.Multi-line Strings (多行字符串)in ES6

    ES6的多行字符串是一个很是实用的功能。在ES5中,咱们不得不使用如下方法来表示多行字符串:

    ?
    1
    2
    3
    4
    5
    6
    7
    var  roadPoem =  'Then took the other, as just as fair,nt'
         'And having perhaps the better claimnt'
         'Because it was grassy and wanted wear,nt'
         'Though as for that the passing therent'
         'Had worn them really about the same,nt' ;
    var  fourAgreements =  'You have the right to be you.n
         You can only be you when you do your best.' ;

    然而在ES6中,仅仅用反引号就能够解决了:

    ?
    1
    2
    3
    4
    5
    6
    7
    var  roadPoem = `Then took the other, as just as fair,
         And having perhaps the better claim
         Because it was grassy and wanted wear,
         Though as  for  that the passing there
         Had worn them really about the same,`;
    var  fourAgreements = `You have the right to be you.
         You can only be you when you  do  your best.`;

    4.Destructuring Assignment (解构赋值)in ES6

    解构多是一个比较难以掌握的概念。先从一个简单的赋值讲起,其中house 和 mouse是key,同时house 和mouse也是一个变量,在ES5中是这样:

    ?
    1
    2
    3
    var  data = $( 'body' ).data(),  // data has properties house and mouse
        house = data.house,
        mouse = data.mouse;

    以及在node.js中用ES5是这样:

    ?
    1
    2
    3
    4
    var  jsonMiddleware = require( 'body-parser' ).jsonMiddleware ;
    var  body = req.body,  // body has username and password
        username = body.username,
        password = body.password;

    在ES6,咱们可使用这些语句代替上面的ES5代码:

    ?
    1
    2
    3
    var  { house, mouse} = $( 'body' ).data();  // we'll get house and mouse variables
    var  {jsonMiddleware} = require('body-parser');
    var  {username, password} = req.body;

    这个一样也适用于数组,很是赞的用法:

    ?
    1
    2
    var  [col1, col2]  = $( '.column' ),
        [line1, line2, line3, , line5] = file.split( 'n' );

    咱们可能须要一些时间来习惯解构赋值语法的使用,可是它确实能给咱们带来许多意外的收获。

    5.Enhanced Object Literals (加强的对象字面量)in ES6

    使用对象文本能够作许多让人意想不到的事情!经过ES6,咱们能够把ES5中的JSON变得更加接近于一个类。

    下面是一个典型ES5对象文本,里面有一些方法和属性:

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    var  serviceBase = {port: 3000, url:  'azat.co' },
         getAccounts =  function (){ return  [1,2,3]};
    var  accountServiceES5 = {
       port: serviceBase.port,
       url: serviceBase.url,
       getAccounts: getAccounts,
        toString:  function () {
           return  JSON.stringify( this .valueOf());
       },
       getUrl:  function () { return  "http://"  this .url +  ':'  this .port},
       valueOf_1_2_3: getAccounts()
    }

    若是咱们想让它更有意思,咱们能够用Object.create从serviceBase继承原型的方法:

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    var  accountServiceES5ObjectCreate = Object.create(serviceBase)
    var  accountServiceES5ObjectCreate = {
       getAccounts: getAccounts,
       toString:  function () {
         return  JSON.stringify( this .valueOf());
       },
       getUrl:  function () { return  "http://"  this .url +  ':'  this .port},
       valueOf_1_2_3: getAccounts()
    }

    咱们知道,accountServiceES5ObjectCreate 和accountServiceES5 并非彻底一致的,由于一个对象(accountServiceES5)在__proto__对象中将有下面这些属性:

    图片1

    为了方便举例,咱们将考虑它们的类似处。因此在ES6的对象文本中,既能够直接分配getAccounts: getAccounts,也能够只需用一个getAccounts,此外,咱们在这里经过__proto__(并非经过’proto’)设置属性,以下所示:

    ?
    1
    2
    3
    4
    5
    var  serviceBase = {port: 3000, url:  'azat.co' },
    getAccounts =  function (){ return  [1,2,3]};
    var  accountService = {
         __proto__: serviceBase,
         getAccounts,

    另外,咱们能够调用super防范,以及使用动态key值(valueOf_1_2_3):

    ?
    1
    2
    3
    4
    5
    6
    7
         toString() {
          return  JSON.stringify(( super .valueOf()));
         },
         getUrl() { return  "http://"  this .url +  ':'  this .port},
         'valueOf_'  + getAccounts().join( '_' ) ]: getAccounts()
    };
    console.log(accountService)

    图片3

    ES6对象文本是一个很大的进步对于旧版的对象文原本说。

    6.Arrow Functions in(箭头函数) ES6

    这是我火烧眉毛想讲的一个特征,CoffeeScript 就是由于它丰富的箭头函数让不少开发者喜好。在ES6中,也有了丰富的箭头函数。这些丰富的箭头是使人惊讶的由于它们将使许多操做变成现实,好比,

    之前咱们使用闭包,this老是预期以外地产生改变,而箭头函数的迷人之处在于,如今你的this能够按照你的预期使用了,身处箭头函数里面,this仍是原来的this。

    有了箭头函数在ES6中, 咱们就没必要用that = this或 self = this 或 _this = this 或.bind(this)。例如,下面的代码用ES5就不是很优雅:

    ?
    1
    2
    3
    4
    var  _this =  this ;
    $( '.btn' ).click( function (event){
       _this.sendData();
    })

    在ES6中就不须要用 _this = this:

    ?
    1
    2
    3
    $( '.btn' ).click((event) =>{
       this .sendData();
    })

    不幸的是,ES6委员会决定,之前的function的传递方式也是一个很好的方案,因此它们仍然保留了之前的功能。

    下面这是一个另外的例子,咱们经过call传递文本给logUpperCase() 函数在ES5中:

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var  logUpperCase =  function () {
       var  _this =  this ;
      
       this .string =  this .string.toUpperCase();
       return  function  () {
         return  console.log(_this.string);
       }
    }
      
    logUpperCase.call({ string:  'ES6 rocks'  })();

    而在ES6,咱们并不须要用_this浪费时间:

    ?
    1
    2
    3
    4
    5
    var  logUpperCase =  function () {
       this .string =  this .string.toUpperCase();
       return  () => console.log( this .string);
    }
    logUpperCase.call({ string:  'ES6 rocks'  })();

    请注意,只要你愿意,在ES6中=>能够混合和匹配老的函数一块儿使用。当在一行代码中用了箭头函数,它就变成了一个表达式。它将暗地里返回单个语句的结果。若是你超过了一行,将须要明确使用return。

    这是用ES5代码建立一个消息数组:

    ?
    1
    2
    3
    4
    var  ids = [ '5632953c4e345e145fdf2df8' , '563295464e345e145fdf2df9' ];
    var  messages = ids.map( function  (value) {
       return  "ID is "  + value;  // explicit return
    });

    用ES6是这样:

    ?
    1
    2
    var  ids = [ '5632953c4e345e145fdf2df8' , '563295464e345e145fdf2df9' ];
    var  messages = ids.map(value => `ID is ${value}`);  // implicit return

    请注意,这里用了字符串模板。

    在箭头函数中,对于单个参数,括号()是可选的,但当你超过一个参数的时候你就须要他们。

    在ES5代码有明确的返回功能:

    ?
    1
    2
    3
    4
    var  ids = [ '5632953c4e345e145fdf2df8' '563295464e345e145fdf2df9' ];
    var  messages = ids.map( function  (value, index, list) {
       return  'ID of '  + index +  ' element is '  + value +  ' ' // explicit return
    });

    在ES6中有更加严谨的版本,参数须要被包含在括号里而且它是隐式的返回:

    ?
    1
    2
    var  ids = [ '5632953c4e345e145fdf2df8' , '563295464e345e145fdf2df9' ];
    var  messages = ids.map((value, index, list) => `ID of ${index} element is ${value} `);  // implicit return

    7. Promises in ES6

    Promises 是一个有争议的话题。所以有许多略微不一样的promise 实现语法。Q,bluebird,deferred.js,vow, avow, jquery 一些能够列出名字的。也有人说咱们不须要promises,仅仅使用异步,生成器,回调等就够了。但使人高兴的是,在ES6中有标准的Promise实 现。

    下面是一个简单的用setTimeout()实现的异步延迟加载函数:

    ?
    1
    2
    3
    setTimeout( function (){
       console.log( 'Yay!' );
    }, 1000);

    在ES6中,咱们能够用promise重写:

    ?
    1
    2
    3
    4
    5
    var  wait1000 =   new  Promise( function (resolve, reject) {
       setTimeout(resolve, 1000);
    }).then( function () {
       console.log( 'Yay!' );
    });

    或者用ES6的箭头函数:

    ?
    1
    2
    3
    4
    5
    var  wait1000 =   new  Promise((resolve, reject)=> {
       setTimeout(resolve, 1000);
    }).then(()=> {
       console.log( 'Yay!' );
    });

    到目前为止,代码的行数从三行增长到五行,并无任何明显的好处。确实,若是咱们有更多的嵌套逻辑在setTimeout()回调函数中,咱们将发现更多好处:

    ?
    1
    2
    3
    4
    5
    6
    setTimeout( function (){
       console.log( 'Yay!' );
       setTimeout( function (){
         console.log( 'Wheeyee!' );
       }, 1000)
    }, 1000);

    在ES6中咱们能够用promises重写:

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    var  wait1000 =  ()=>  new  Promise((resolve, reject)=> {setTimeout(resolve, 1000)});
    wait1000()
         .then( function () {
             console.log( 'Yay!' )
             return  wait1000()
         })
         .then( function () {
             console.log( 'Wheeyee!' )
         });

    仍是不确信Promises 比普通回调更好?其实我也不确信,我认为一旦你有回调的想法,那么就没有必要额外增长promises的复杂性。

    虽然,ES6 有让人崇拜的Promises 。Promises 是一个有利有弊的回调可是确实是一个好的特性,更多详细的信息关于promise:Introduction to ES6 Promises.

    8.Block-Scoped Constructs Let and Const(块做用域和构造let和const)

    在ES6代码中,你可能已经看到那熟悉的身影let。在ES6里let并非一个花俏的特性,它是更复杂的。Let是一种新的变量申明方式,它容许你把变量做用域控制在块级里面。咱们用大括号定义代码块,在ES5中,块级做用域起不了任何做用:

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    function  calculateTotalAmount (vip) {
       var  amount = 0;
       if  (vip) {
         var  amount = 1;
       }
       // more crazy blocks!
         var  amount = 100;
         {
           var  amount = 1000;
         }
       }  
       return  amount;
    }
    console.log(calculateTotalAmount( true ));

    结果将返回1000,这真是一个bug。在ES6中,咱们用let限制块级做用域。而var是限制函数做用域。

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    function  calculateTotalAmount (vip) {
       var  amount = 0;  // probably should also be let, but you can mix var and let
       if  (vip) {
         let  amount = 1;  // first amount is still 0
      
       // more crazy blocks!
         let  amount = 100;  // first amount is still 0
         {
           let  amount = 1000;  // first amount is still 0
         }
       }  
       return  amount;
    }
      
    console.log(calculateTotalAmount( true ));

    这个结果将会是0,由于块做用域中有了let。若是(amount=1).那么这个表达式将返回1。谈到const,就更加容易了;它就是一个不变量,也是块级做用域就像let同样。下面是一个演示,这里有一堆常量,它们互不影响,由于它们属于不一样的块级做用域:

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    function  calculateTotalAmount (vip) {
       const amount = 0;  
       if  (vip) {
         const amount = 1;
      
       // more crazy blocks!
         const amount = 100 ;
         {
           const amount = 1000;
         }
       }  
       return  amount;
    }
    console.log(calculateTotalAmount( true ));

    从我我的看来,let 和const使这个语言变复杂了。没有它们的话,咱们只需考虑一种方式,如今有许多种场景须要考虑。

    9. Classes (类)in ES6

    若是你喜欢面向对象编程(OOP),那么你将喜好这个特性。之后写一个类和继承将变得跟在facebook上写一个评论那么容易。

    类的建立和使用真是一件使人头疼的事情在过去的ES5中,由于没有一个关键字class (它被保留,可是什么也不能作)。在此之上,大量的继承模型像pseudo classicalclassicalfunctional 更加增长了混乱,JavaScript 之间的宗教战争只会更加火上浇油。

    用ES5写一个类,有不少种方法,这里就先不说了。如今就来看看如何用ES6写一个类吧。ES6没有用函数, 而是使用原型实现类。咱们建立一个类baseModel ,而且在这个类里定义了一个constructor 和一个 getName()方法:

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class  baseModel {
       constructor(options, data) {  // class constructor,node.js 5.6暂时不支持options = {}, data = []这样传参
         this .name =  'Base' ;
         this .url =  'http://azat.co/api' ;
         this .data = data;
         this .options = options;
        }
      
         getName() {  // class method
             console.log(`Class name: ${ this .name}`);
         }
    }

    注意咱们对options 和data使用了默认参数值。此外方法名也不须要加function关键字,并且冒号(:)也不须要了。另一个大的区别就是你不须要分配属性this。如今设置一个属性的值,只需简单的在构造函数中分配。

    AccountModel 从类baseModel 中继承而来:

    ?
    1
    2
    class  AccountModel  extends  baseModel {
         constructor(options, data) {

    为了调用父级构造函数,能够绝不费力的唤起super()用参数传递:

    ?
    1
    2
    3
    4
    super ({ private true }, [ '32113123123' '524214691' ]);  //call the parent method with super
            this .name =  'Account Model' ;
            this .url += '/accounts/' ;
         }

    若是你想作些更好玩的,你能够把 accountData 设置成一个属性:

    ?
    1
    2
    3
    4
    5
         get accountsData() {  //calculated attribute getter
         // ... make XHR
             return  this .data;
         }
    }

    那么,你如何调用他们呢?它是很是容易的:

    ?
    1
    2
    3
    let  accounts =  new  AccountModel(5);
    accounts.getName();
    console.log( 'Data is %s' , accounts.accountsData);

    结果使人惊讶,输出是:

    Class name: Account Model

    Data is 32113123123,524214691

    10. Modules (模块)in ES6

    众所周知,在ES6之前JavaScript并不支持本地的模块。人们想出了AMD,RequireJS,CommonJS以及其它解决方法。如今ES6中能够用模块import 和export 操做了。

    在ES5中,你能够在<script>中直接写能够运行的代码(简称IIFE),或者一些库像AMD。然而在ES6中,你能够用export导入你的类。下面举个例子,在ES5中,module.js有port变量和getAccounts 方法:

    ?
    1
    module.exports = {  port: 3000,  getAccounts:  function () {    ...  }}

    在ES5中,main.js须要依赖require(‘module’) 导入module.js:

    ?
    1
    var  service = require( 'module.js' );console.log(service.port);  // 3000

    但在ES6中,咱们将用export and import。例如,这是咱们用ES6 写的module.js文件库:

    ?
    1
    export  var  port = 3000; export  function  getAccounts(url) {  ...}

    若是用ES6来导入到文件main.js中,咱们需用import {name} from ‘my-module’语法,例如:

    ?
    1
    import  {port, getAccounts} from  'module' ;console.log(port);  // 3000

    或者咱们能够在main.js中把整个模块导入, 并命名为 service:

    ?
    1
    import  * as service from  'module' ;console.log(service.port);  // 3000

    从我我的角度来讲,我以为ES6模块是让人困惑的。但能够确定的事,它们使语言更加灵活了。

    并非全部的浏览器都支持ES6模块,因此你须要使用一些像jspm去支持ES6模块。

    更多的信息和例子关于ES6模块,请看 this text无论怎样,请写模块化的JavaScript。

    如何使用ES6 (Babel)

    ES6已经敲定,但并非全部的浏览器都彻底支持,详见:http://kangax.github.io/compat-table/es6/。要使用ES6,须要一个编译器例如:babel。你能够把它做为一个独立的工具使用,也能够把它放在构建中。grunt,gulp和webpack中都有能够支持babel的插件。

    2.png

    这是一个gulp案列,安装gulp-babel插件:

    ?
    1
    $ npm  install  --save-dev gulp-babel

    在gulpfile.js中,定义一个任务build,放入src/app.js,而且编译它进入构建文件中。

    ?
    1
    var  gulp = require( 'gulp' ),  babel = require( 'gulp-babel' );gulp.task( 'build' function  () {   return  gulp.src( 'src/app.js' )    .pipe(babel())    .pipe(gulp.dest( 'build' ));})

    Node.js and ES6

    在nodejs中,你能够用构建工具或者独立的Babel模块 babel-core 来编译你的Node.js文件。安装以下:

    ?
    1
    $ npm  install  --save-dev babel-core

    而后在node.js中,你能够调用这个函数:

    ?
    1
    require( "babel-core" ).transform(ES5Code, options);

    ES6总结

    这里还有许多ES6的其它特性你可能会使用到,排名不分前后:

    一、全新的Math, Number, String, Array 和 Object 方法

    二、二进制和八进制数据类型

    三、默认参数不定参数扩展运算符

    四、Symbols符号

    五、tail调用

    六、Generators (生成器)

    七、New data structures like Map and Set(新的数据构造对像MAP和set)

    参考文献:

    1. ES6 Cheatsheet (FREE PDF)

    2. http://webapplog.com/ES6/comment-page-1/

    3. Understanding ECMAScript 6 by Nicolas Zakas book

    4. http://ES6-features.org/#DateTimeFormatting

    5. IIFE:马上运行的函数表达式

相关文章
相关标签/搜索