如下是ES6排名前十的最佳特性列表(排名不分前後):javascript
聲明:這些列表僅是我的主觀意見。它毫不是爲了削弱ES6其它功能,這裏只列出了10條比較經常使用的特性。html
還記得咱們之前不得不經過下面方式來定義默認參數:java
1 var link = function (height, color, url) { 2 var height = height || 50; 3 var color = color || 'red'; 4 var url = url || 'http://azat.co'; 5 ... 6 }
一切工做都是正常的,直到參數值是0後,就有問題了,由於在JavaScript中,0表示fasly,它是默認被hard-coded的值,而不能變成參數自己的值。固然,若是你非要用0做爲值,咱們能夠忽略這一缺陷而且使用邏輯OR就好了!但在ES6,咱們能夠直接把默認值放在函數申明裏:node
1 var link = function(height = 50, color = 'red', url = 'http://azat.co') { 2 ... 3 }
順便說一句,這個語法相似於Ruby!jquery
在其它語言中,使用模板和插入值是在字符串裏面輸出變量的一種方式。所以,在ES5,咱們能夠這樣組合一個字符串:webpack
1 var name = 'Your name is ' + first + ' ' + last + '.'; 2 var url = 'http://localhost:3000/api/messages/' + id;
幸運的是,在ES6中,咱們可使用新的語法$ {NAME},並把它放在反引號裏:git
1 var name = `Your name is ${first} ${last}. `; 2 var url = `http://localhost:3000/api/messages/${id}`;
ES6的多行字符串是一個很是實用的功能。在ES5中,咱們不得不使用如下方法來表示多行字符串:es6
1 var roadPoem = 'Then took the other, as just as fair,nt' 2 + 'And having perhaps the better claimnt' 3 + 'Because it was grassy and wanted wear,nt' 4 + 'Though as for that the passing therent' 5 + 'Had worn them really about the same,nt'; 6 var fourAgreements = 'You have the right to be you.n 7 You can only be you when you do your best.';
然而在ES6中,僅僅用反引號就能夠解決了:github
1 var roadPoem = `Then took the other, as just as fair, 2 And having perhaps the better claim 3 Because it was grassy and wanted wear, 4 Though as for that the passing there 5 Had worn them really about the same,`; 6 var fourAgreements = `You have the right to be you. 7 You can only be you when you do your best.`;
解構多是一個比較難以掌握的概念。先從一個簡單的賦值講起,其中house 和 mouse是key,同時house 和mouse也是一個變量,在ES5中是這樣:web
1 var data = $('body').data(), // data has properties house and mouse 2 house = data.house, 3 mouse = data.mouse;
以及在node.js中用ES5是這樣:
1 var jsonMiddleware = require('body-parser').jsonMiddleware ; 2 var body = req.body, // body has username and password 3 username = body.username, 4 password = body.password;
在ES6,咱們可使用這些語句代替上面的ES5代碼:
1 var { house, mouse} = $('body').data(); // we'll get house and mouse variables 2 var {jsonMiddleware} = require('body-parser'); 3 var {username, password} = req.body;
這個一樣也適用於數組,很是讚的用法:
1 var [col1, col2] = $('.column'), 2 [line1, line2, line3, , line5] = file.split('n');
咱們可能須要一些時間來習慣解構賦值語法的使用,可是它確實能給咱們帶來許多意外的收穫。
使用對象文本能夠作許多讓人意想不到的事情!經過ES6,咱們能夠把ES5中的JSON變得更加接近於一個類。
下面是一個典型ES5對象文本,裏面有一些方法和屬性:
1 var serviceBase = {port: 3000, url: 'azat.co'}, 2 getAccounts = function(){return [1,2,3]}; 3 var accountServiceES5 = { 4 port: serviceBase.port, 5 url: serviceBase.url, 6 getAccounts: getAccounts, 7 toString: function() { 8 return JSON.stringify(this.valueOf()); 9 }, 10 getUrl: function() {return "http://" + this.url + ':' + this.port}, 11 valueOf_1_2_3: getAccounts() 12 }
若是咱們想讓它更有意思,咱們能夠用Object.create從serviceBase繼承原型的方法:
1 var accountServiceES5ObjectCreate = Object.create(serviceBase) 2 var accountServiceES5ObjectCreate = { 3 getAccounts: getAccounts, 4 toString: function() { 5 return JSON.stringify(this.valueOf()); 6 }, 7 getUrl: function() {return "http://" + this.url + ':' + this.port}, 8 valueOf_1_2_3: getAccounts() 9 }
咱們知道,accountServiceES5ObjectCreate 和accountServiceES5 並非徹底一致的,由於一個對象(accountServiceES5)在__proto__對象中將有下面這些屬性:
爲了方便舉例,咱們將考慮它們的類似處。因此在ES6的對象文本中,既能夠直接分配getAccounts: getAccounts,也能夠只需用一個getAccounts,此外,咱們在這裏經過__proto__(並非經過’proto’)設置屬性,以下所示:
1 var serviceBase = {port: 3000, url: 'azat.co'}, 2 getAccounts = function(){return [1,2,3]}; 3 var accountService = { 4 __proto__: serviceBase, 5 getAccounts,
另外,咱們能夠調用super防範,以及使用動態key值(valueOf_1_2_3):
1 toString() { 2 return JSON.stringify((super.valueOf())); 3 }, 4 getUrl() {return "http://" + this.url + ':' + this.port}, 5 [ 'valueOf_' + getAccounts().join('_') ]: getAccounts() 6 }; 7 console.log(accountService)
ES6對象文本是一個很大的進步對於舊版的對象文原本說。
這是我火燒眉毛想講的一個特徵,CoffeeScript 就是由於它豐富的箭頭函數讓不少開發者喜好。在ES6中,也有了豐富的箭頭函數。這些豐富的箭頭是使人驚訝的由於它們將使許多操做變成現實,好比,
之前咱們使用閉包,this老是預期以外地產生改變,而箭頭函數的迷人之處在於,如今你的this能夠按照你的預期使用了,身處箭頭函數裏面,this仍是原來的this。
有了箭頭函數在ES6中, 咱們就沒必要用that = this或 self = this 或 _this = this 或.bind(this)。例如,下面的代碼用ES5就不是很優雅:
1 var _this = this; 2 $('.btn').click(function(event){ 3 _this.sendData(); 4 })
在ES6中就不須要用 _this = this:
1 $('.btn').click((event) =>{ 2 this.sendData(); 3 })
不幸的是,ES6委員會決定,之前的function的傳遞方式也是一個很好的方案,因此它們仍然保留了之前的功能。
下面這是一個另外的例子,咱們經過call傳遞文本給logUpperCase() 函數在ES5中:
1 var logUpperCase = function() { 2 var _this = this; 3 4 this.string = this.string.toUpperCase(); 5 return function () { 6 return console.log(_this.string); 7 } 8 } 9 10 logUpperCase.call({ string: 'ES6 rocks' })();
而在ES6,咱們並不須要用_this浪費時間:
1 var logUpperCase = function() { 2 this.string = this.string.toUpperCase(); 3 return () => console.log(this.string); 4 } 5 logUpperCase.call({ string: 'ES6 rocks' })();
請注意,只要你願意,在ES6中=>能夠混合和匹配老的函數一塊兒使用。當在一行代碼中用了箭頭函數,它就變成了一個表達式。它將暗地裏返回單個語句的結果。若是你超過了一行,將須要明確使用return。
這是用ES5代碼建立一個消息數組:
1 var ids = ['5632953c4e345e145fdf2df8','563295464e345e145fdf2df9']; 2 var messages = ids.map(function (value) { 3 return "ID is " + value; // explicit return 4 });
用ES6是這樣:
1 var ids = ['5632953c4e345e145fdf2df8','563295464e345e145fdf2df9']; 2 var messages = ids.map(value => `ID is ${value}`); // implicit return
請注意,這裏用了字符串模板。
在箭頭函數中,對於單個參數,括號()是可選的,但當你超過一個參數的時候你就須要他們。
在ES5代碼有明確的返回功能:
1 var ids = ['5632953c4e345e145fdf2df8', '563295464e345e145fdf2df9']; 2 var messages = ids.map(function (value, index, list) { 3 return 'ID of ' + index + ' element is ' + value + ' '; // explicit return 4 });
在ES6中有更加嚴謹的版本,參數須要被包含在括號裏而且它是隱式的返回:
1 var ids = ['5632953c4e345e145fdf2df8','563295464e345e145fdf2df9']; 2 var messages = ids.map((value, index, list) => `ID of ${index} element is ${value} `); // implicit return
Promises 是一個有爭議的話題。所以有許多略微不一樣的promise 實現語法。Q,bluebird,deferred.js,vow, avow, jquery 一些能夠列出名字的。也有人說咱們不須要promises,僅僅使用異步,生成器,回調等就夠了。但使人高興的是,在ES6中有標準的Promise實現。
下面是一個簡單的用setTimeout()實現的異步延遲加載函數:
1 setTimeout(function(){ 2 console.log('Yay!'); 3 }, 1000);
在ES6中,咱們能夠用promise重寫:
1 var wait1000 = new Promise(function(resolve, reject) { 2 setTimeout(resolve, 1000); 3 }).then(function() { 4 console.log('Yay!'); 5 });
或者用ES6的箭頭函數:
1 var wait1000 = new Promise((resolve, reject)=> { 2 setTimeout(resolve, 1000); 3 }).then(()=> { 4 console.log('Yay!'); 5 });
到目前爲止,代碼的行數從三行增長到五行,並無任何明顯的好處。確實,若是咱們有更多的嵌套邏輯在setTimeout()回調函數中,咱們將發現更多好處:
1 setTimeout(function(){ 2 console.log('Yay!'); 3 setTimeout(function(){ 4 console.log('Wheeyee!'); 5 }, 1000) 6 }, 1000);
在ES6中咱們能夠用promises重寫:
1 var wait1000 = ()=> new Promise((resolve, reject)=> {setTimeout(resolve, 1000)}); 2 wait1000() 3 .then(function() { 4 console.log('Yay!') 5 return wait1000() 6 }) 7 .then(function() { 8 console.log('Wheeyee!') 9 });
仍是不確信Promises 比普通回調更好?其實我也不確信,我認爲一旦你有回調的想法,那麼就沒有必要額外增長promises的複雜性。
雖然,ES6 有讓人崇拜的Promises 。Promises 是一個有利有弊的回調可是確實是一個好的特性,更多詳細的信息關於promise:Introduction to ES6 Promises.
在ES6代碼中,你可能已經看到那熟悉的身影let。在ES6裏let並非一個花俏的特性,它是更復雜的。Let是一種新的變量申明方式,它容許你把變量做用域控制在塊級裏面。咱們用大括號定義代碼塊,在ES5中,塊級做用域起不了任何做用:
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 function calculateTotalAmount (vip) { 2 var amount = 0; // probably should also be let, but you can mix var and let 3 if (vip) { 4 let amount = 1; // first amount is still 0 5 } 6 { // more crazy blocks! 7 let amount = 100; // first amount is still 0 8 { 9 let amount = 1000; // first amount is still 0 10 } 11 } 12 return amount; 13 } 14 15 console.log(calculateTotalAmount(true));
這個結果將會是0,由於塊做用域中有了let。若是(amount=1).那麼這個表達式將返回1。談到const,就更加容易了;它就是一個不變量,也是塊級做用域就像let同樣。下面是一個演示,這裏有一堆常量,它們互不影響,由於它們屬於不一樣的塊級做用域:
1 function calculateTotalAmount (vip) { 2 const amount = 0; 3 if (vip) { 4 const amount = 1; 5 } 6 { // more crazy blocks! 7 const amount = 100 ; 8 { 9 const amount = 1000; 10 } 11 } 12 return amount; 13 } 14 console.log(calculateTotalAmount(true));
從我我的看來,let 和const使這個語言變複雜了。沒有它們的話,咱們只需考慮一種方式,如今有許多種場景須要考慮。
若是你喜歡面向對象編程(OOP),那麼你將喜好這個特性。之後寫一個類和繼承將變得跟在facebook上寫一個評論那麼容易。
類的建立和使用真是一件使人頭疼的事情在過去的ES5中,由於沒有一個關鍵字class (它被保留,可是什麼也不能作)。在此之上,大量的繼承模型像pseudo classical, classical, functional 更加增長了混亂,JavaScript 之間的宗教戰爭只會更加火上澆油。
用ES5寫一個類,有不少種方法,這裏就先不說了。如今就來看看如何用ES6寫一個類吧。ES6沒有用函數, 而是使用原型實現類。咱們建立一個類baseModel ,而且在這個類裏定義了一個constructor 和一個 getName()方法:
1 class baseModel { 2 constructor(options, data) { // class constructor,node.js 5.6暫時不支持options = {}, data = []這樣傳參 3 this.name = 'Base'; 4 this.url = 'http://azat.co/api'; 5 this.data = data; 6 this.options = options; 7 } 8 9 getName() { // class method 10 console.log(`Class name: ${this.name}`); 11 } 12 }
注意咱們對options 和data使用了默認參數值。此外方法名也不須要加function關鍵字,並且冒號(:)也不須要了。另一個大的區別就是你不須要分配屬性this。如今設置一個屬性的值,只需簡單的在構造函數中分配。
AccountModel 從類baseModel 中繼承而來:
1 class AccountModel extends baseModel { 2 constructor(options, data) {
爲了調用父級構造函數,能夠絕不費力的喚起super()用參數傳遞:
1 super({private: true}, ['32113123123', '524214691']); //call the parent method with super 2 this.name = 'Account Model'; 3 this.url +='/accounts/'; 4 }
若是你想作些更好玩的,你能夠把 accountData 設置成一個屬性:
1 get accountsData() { //calculated attribute getter 2 // ... make XHR 3 return this.data; 4 } 5 }
那麼,你如何調用他們呢?它是很是容易的:
1 let accounts = new AccountModel(5); 2 accounts.getName(); 3 console.log('Data is %s', accounts.accountsData);
結果使人驚訝,輸出是:
Class name: Account Model
Data is 32113123123,524214691
衆所周知,在ES6之前JavaScript並不支持本地的模塊。人們想出了AMD,RequireJS,CommonJS以及其它解決方法。如今ES6中能夠用模塊import 和export 操做了。
在ES5中,你能夠在 <script>中直接寫能夠運行的代碼(簡稱IIFE),或者一些庫像AMD。然而在ES6中,你能夠用export導入你的類。下面舉個例子,在ES5中,module.js有port變量和getAccounts 方法:
1 module.exports = { 2 port: 3000, 3 getAccounts: function() { 4 ... 5 } 6 }
在ES5中,main.js須要依賴require(‘module’) 導入module.js:
1 var service = require('module.js'); 2 console.log(service.port); // 3000
但在ES6中,咱們將用export and import。例如,這是咱們用ES6 寫的module.js文件庫:
1 export var port = 3000; 2 export function getAccounts(url) { 3 ... 4 }
若是用ES6來導入到文件main.js中,咱們需用import {name} from ‘my-module’語法,例如:
1 import {port, getAccounts} from 'module'; 2 console.log(port); // 3000
或者咱們能夠在main.js中把整個模塊導入, 並命名爲 service:
1 import * as service from 'module'; 2 console.log(service.port); // 3000
從我我的角度來講,我以爲ES6模塊是讓人困惑的。但能夠確定的事,它們使語言更加靈活了。
並非全部的瀏覽器都支持ES6模塊,因此你須要使用一些像jspm去支持ES6模塊。
更多的信息和例子關於ES6模塊,請看 this text。無論怎樣,請寫模塊化的JavaScript。
ES6已經敲定,但並非全部的瀏覽器都徹底支持,詳見:http://kangax.github.io/compat-table/es6/。要使用ES6,須要一個編譯器例如:babel。你能夠把它做爲一個獨立的工具使用,也能夠把它放在構建中。grunt,gulp和webpack中都有能夠支持babel的插件。
這是一個gulp案列,安裝gulp-babel插件:
1 $ npm install --save-dev gulp-babel
在gulpfile.js中,定義一個任務build,放入src/app.js,而且編譯它進入構建文件中。
1 var gulp = require('gulp'), 2 babel = require('gulp-babel'); 3 gulp.task('build', function () { 4 return gulp.src('src/app.js') 5 .pipe(babel()) 6 .pipe(gulp.dest('build')); 7 })
在nodejs中,你能夠用構建工具或者獨立的Babel模塊 babel-core 來編譯你的Node.js文件。安裝以下:
1 $ npm install --save-dev babel-core
而後在node.js中,你能夠調用這個函數:
1 require("babel-core").transform(ES5Code, options);
這裏還有許多ES6的其它特性你可能會使用到,排名不分前後:
一、全新的Math, Number, String, Array 和 Object 方法
二、二進制和八進制數據類型
三、默認參數不定參數擴展運算符
四、Symbols符號
五、tail調用
六、Generators (生成器)
七、New data structures like Map and Set(新的數據構造對像MAP和set)