還記得咱們之前不得不經過下面方式來定義默認參數:javascript
但在ES6,咱們能夠直接把默認值放在函數申明裏:html
var link = function(height = 50, color = 'red', url = 'http://azat.co') { ... }
在其它語言中,使用模板和插入值是在字符串裏面輸出變量的一種方式。所以,在ES5,咱們能夠這樣組合一個字符串:java
var name = 'Your name is ' + first + ' ' + last + '.'; var url = 'http://localhost:3000/api/messages/' + id;
在ES6中,咱們可使用新的語法$ {NAME},並把它放在反引號裏:node
var name = `Your name is ${first} ${last}. `; var url = `http://localhost:3000/api/messages/${id}`;
ES6的多行字符串是一個很是實用的功能。在ES5中,咱們不得不使用如下方法來表示多行字符串: jquery
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中,僅僅用反引號就能夠解決了: webpack
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.`;
使用對象文本能夠作許多讓人意想不到的事情!經過ES6,咱們能夠把ES5中的JSON變得更加接近於一個類。git
下面是一個典型ES5對象文本,裏面有一些方法和屬性:es6
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繼承原型的方法:github
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__對象中將有下面這些屬性:web
爲了方便舉例,咱們將考慮它們的類似處。因此在ES6的對象文本中,既能夠直接分配getAccounts: getAccounts,也能夠只需用一個getAccounts,此外,咱們在這裏經過__proto__(並非經過’proto’)設置屬性,以下所示:
var serviceBase = {port: 3000, url: 'azat.co'}, getAccounts = function(){return [1,2,3]}; var accountService = { __proto__: serviceBase, getAccounts,
另外,咱們能夠調用super防範,以及使用動態key值(valueOf_1_2_3):
toString() { return JSON.stringify((super.valueOf())); }, getUrl() {return "http://" + this.url + ':' + this.port}, [ 'valueOf_' + getAccounts().join('_') ]: getAccounts() }; console.log(accountService)
ES6對象文本是一個很大的進步對於舊版的對象文原本說。
有了箭頭函數在ES6中, 咱們就沒必要用that = this或 self = this 或 _this = this 或.bind(this)。例如,下面的代碼用ES5就不是很優雅:
var _this = this; $('.btn').click(function(event){ _this.sendData(); })
在ES6中就不須要用 _this = this:
$('.btn').click((event) =>{ this.sendData(); })
下面這是一個另外的例子,咱們經過call傳遞文本給logUpperCase() 函數在ES5中:
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浪費時間:
var logUpperCase = function() { this.string = this.string.toUpperCase(); return () => console.log(this.string); } logUpperCase.call({ string: 'ES6 rocks' })();
請注意,只要你願意,在ES6中=>能夠混合和匹配老的函數一塊兒使用。當在一行代碼中用了箭頭函數,它就變成了一個表達式。它將暗地裏返回單個語句的結果。若是你超過了一行,將須要明確使用return。
這是用ES5代碼建立一個消息數組:
var ids = ['5632953c4e345e145fdf2df8','563295464e345e145fdf2df9']; var messages = ids.map(function (value) { return "ID is " + value; // explicit return });
用ES6是這樣:
var ids = ['5632953c4e345e145fdf2df8','563295464e345e145fdf2df9']; var messages = ids.map(value => `ID is ${value}`); // implicit return
請注意,這裏用了字符串模板。
在箭頭函數中,對於單個參數,括號()是可選的,但當你超過一個參數的時候你就須要他們。
在ES5代碼有明確的返回功能:
var ids = ['5632953c4e345e145fdf2df8', '563295464e345e145fdf2df9']; var messages = ids.map(function (value, index, list) { return 'ID of ' + index + ' element is ' + value + ' '; // explicit return });
在ES6中有更加嚴謹的版本,參數須要被包含在括號裏而且它是隱式的返回:
var ids = ['5632953c4e345e145fdf2df8','563295464e345e145fdf2df9']; 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()實現的異步延遲加載函數:
setTimeout(function(){ console.log('Yay!'); }, 1000);
在ES6中,咱們能夠用promise重寫:
var wait1000 = new Promise(function(resolve, reject) { setTimeout(resolve, 1000); }).then(function() { console.log('Yay!'); });
或者用ES6的箭頭函數:
var wait1000 = new Promise((resolve, reject)=> { setTimeout(resolve, 1000); }).then(()=> { console.log('Yay!'); });
到目前爲止,代碼的行數從三行增長到五行,並無任何明顯的好處。確實,若是咱們有更多的嵌套邏輯在setTimeout()回調函數中,咱們將發現更多好處:
setTimeout(function(){ console.log('Yay!'); setTimeout(function(){ console.log('Wheeyee!'); }, 1000) }, 1000);
在ES6中咱們能夠用promises重寫:
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.
在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是限制函數做用域。
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同樣。下面是一個演示,這裏有一堆常量,它們互不影響,由於它們屬於不一樣的塊級做用域:
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使這個語言變複雜了。沒有它們的話,咱們只需考慮一種方式,如今有許多種場景須要考慮。
若是你喜歡面向對象編程(OOP),那麼你將喜好這個特性。之後寫一個類和繼承將變得跟在facebook上寫一個評論那麼容易。
類的建立和使用真是一件使人頭疼的事情在過去的ES5中,由於沒有一個關鍵字class (它被保留,可是什麼也不能作)。在此之上,大量的繼承模型像pseudo classical, classical, functional 更加增長了混亂,JavaScript 之間的宗教戰爭只會更加火上澆油。
用ES5寫一個類,有不少種方法,這裏就先不說了。如今就來看看如何用ES6寫一個類吧。ES6沒有用函數, 而是使用原型實現類。咱們建立一個類baseModel ,而且在這個類裏定義了一個constructor 和一個 getName()方法:
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 中繼承而來:
class AccountModel extends baseModel {
constructor(options, data) {
爲了調用父級構造函數,能夠絕不費力的喚起super()用參數傳遞:
super({private: true}, ['32113123123', '524214691']); //call the parent method with super this.name = 'Account Model'; this.url +='/accounts/'; }
若是你想作些更好玩的,你能夠把 accountData 設置成一個屬性:
get accountsData() { //calculated attribute getter // ... make XHR return this.data; } }
那麼,你如何調用他們呢?它是很是容易的:
let accounts = new AccountModel(5); accounts.getName(); 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 方法:
module.exports = { port: 3000, getAccounts: function() { ... } }
在ES5中,main.js須要依賴require(‘module’) 導入module.js:
var service = require('module.js'); console.log(service.port); // 3000
但在ES6中,咱們將用export and import。例如,這是咱們用ES6 寫的module.js文件庫:
export var port = 3000; export function getAccounts(url) { ... }
若是用ES6來導入到文件main.js中,咱們需用import {name} from ‘my-module’語法,例如:
import {port, getAccounts} from 'module'; console.log(port); // 3000
或者咱們能夠在main.js中把整個模塊導入, 並命名爲 service:
import * as service from 'module'; 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插件:
$ npm install --save-dev gulp-babel
在gulpfile.js中,定義一個任務build,放入src/app.js,而且編譯它進入構建文件中。
在nodejs中,你能夠用構建工具或者獨立的Babel模塊 babel-core 來編譯你的Node.js文件。安裝以下:
$ npm install --save-dev babel-core
而後在node.js中,你能夠調用這個函數:
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)