es6的十大特性
https://blog.csdn.net/persistencegoing/article/details/84376427
ES6(ECMAScript2015)的出現,無疑給前端開發人員帶來了新的驚喜,它包含了一些很棒的新特性,可以更加方便的實現很多複雜的操作,提高開發人員的效率。
本文主要針對ES6做一個簡要介紹。 主要譯自: http://webapplog.com/ES6/comment-page-1/。也許你還不知道ES6是什麼, 實際上, 它是一種新的javascript規範。在這個大家都很忙碌的時代,如果你想對ES6有一個快速的瞭解,那麼請繼續往下讀,去了解當今最流行的程式語言JavaScript最新一代的十大特性。
以下是ES6排名前十的最佳特性列表(排名不分先後):
- Default Parameters(預設引數) in ES6
- Template Literals (模板文字)in ES6
- Multi-line Strings (多行字串)in ES6
- Destructuring Assignment (解構賦值)in ES6
- Enhanced Object Literals (增強的物件文字)in ES6
- Arrow Functions (箭頭函式)in ES6
- Promises in ES6
- Block-Scoped Constructs Let and Const(塊作用域構造Let and Const)
- Classes(類) in ES6
- Modules(模組) in ES6
宣告:這些列表僅是個人主觀意見。它絕不是為了削弱ES6其它功能,這裡只列出了10條比較常用的特性。
首先回顧一下JavaScript的歷史,不清楚歷史的人,很難理解JavaScript為什麼會這樣發展。下面就是一個簡單的JavaScript發展時間軸:
1、1995:JavaScript誕生,它的初始名叫LiveScript。
2、1997:ECMAScript標準確立。
3、1999:ES3出現,與此同時IE5風靡一時。
4、2000–2005: XMLHttpRequest又名AJAX, 在Outlook Web Access (2000)、Oddpost (2002),Gmail (2004)和Google Maps (2005)大受重用。
5、2009: ES5出現,(就是我們大多數人現在使用的)例如foreach,Object.keys,Object.create和JSON標準。
6、2015:ES6/ECMAScript2015出現。
歷史回顧就先到此,現讓我們進入正題。
1.Default Parameters(預設引數) in ES6
還記得我們以前不得不通過下面方式來定義預設引數:
-
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,我們可以直接把預設值放在函式申明裡:
-
var link = function(height = 50, color = 'red', url = 'http://azat.co') {
-
...
-
}
順便說一句,這個語法類似於Ruby
!
2.Template Literals(模板物件) in ES6
在其它語言中,使用模板和插入值是在字串裡面輸出變數的一種方式。因此,在ES5,我們可以這樣組合一個字串:
-
var name = 'Your name is ' + first + ' ' + last + '.';
-
var url = 'http://localhost:3000/api/messages/' + id;
幸運的是,在ES6中,我們可以使用新的語法$ {NAME},並把它放在反引號裡:
-
var name = `Your name is ${first} ${last}. `;
-
var url = `http://localhost:3000/api/messages/${id}`;
3.Multi-line Strings (多行字串)in ES6
ES6的多行字串是一個非常實用的功能。在ES5中,我們不得不使用以下方法來表示多行字串:
-
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中,僅僅用反引號就可以解決了:
-
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中是這樣:
-
var data = $('body').data(), // data has properties house and mouse
-
house = data.house,
-
mouse = data.mouse;
以及在node.js中用ES5是這樣:
-
var jsonMiddleware = require('body-parser').jsonMiddleware ;
-
var body = req.body, // body has username and password
-
username = body.username,
-
password = body.password;
在ES6,我們可以使用這些語句代替上面的ES5程式碼:
-
var { house, mouse} = $('body').data(); // we'll get house and mouse variables
-
var {jsonMiddleware} = require('body-parser');
-
var {username, password} = req.body;
這個同樣也適用於陣列,非常讚的用法:
-
var [col1, col2] = $('.column'),
-
[line1, line2, line3, , line5] = file.split('n');
我們可能需要一些時間來習慣解構賦值語法的使用,但是它確實能給我們帶來許多意外的收穫。
5.Enhanced Object Literals (增強的物件字面量)in ES6
使用物件文字可以做許多讓人意想不到的事情!通過ES6,我們可以把ES5中的JSON變得更加接近於一個類。
下面是一個典型ES5物件文字,裡面有一些方法和屬性:
-
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繼承原型的方法:
-
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物件中將有下面這些屬性:
new1
為了方便舉例,我們將考慮它們的相似處。所以在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)
new2
ES6物件文字是一個很大的進步對於舊版的物件文字來說。
6.Arrow Functions in(箭頭函式) ES6
這是我迫不及待想講的一個特徵,CoffeeScript 就是因為它豐富的箭頭函式讓很多開發者喜愛。在ES6中,也有了豐富的箭頭函式。這些豐富的箭頭是令人驚訝的因為它們將使許多操作變成現實,比如,
以前我們使用閉包,this總是預期之外地產生改變,而箭頭函式的迷人之處在於,現在你的this可以按照你的預期使用了,身處箭頭函式裡面,this還是原來的this。
有了箭頭函式在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();
-
})
不幸的是,ES6委員會決定,以前的function的傳遞方式也是一個很好的方案,所以它們仍然保留了以前的功能。
下面這是一個另外的例子,我們通過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
7. Promises in ES6
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.
8.Block-Scoped Constructs Let and Const(塊作用域和構造let和const)**
在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使這個語言變複雜了。沒有它們的話,我們只需考慮一種方式,現在有許多種場景需要考慮。
9. Classes (類)in ES6
如果你喜歡面向物件程式設計(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
10. Modules (模組)in ES6
眾所周知,在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 (Babel)
ES6已經敲定,但並不是所有的瀏覽器都完全支援,詳見:http://kangax.github.io/compat-table/es6/。要使用ES6,需要一個編譯器例如:babel。你可以把它作為一個獨立的工具使用,也可以把它放在構建中。grunt,gulp和webpack中都有可以支援babel的外掛。
6941baebjw1f61bokq3xbj20yb0pdq6a
這是一個gulp案列,安裝gulp-babel外掛:
$ npm install --save-dev gulp-babel
在gulpfile.js中,定義一個任務build,放入src/app.js,並且編譯它進入構建檔案中。
-
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檔案。安裝如下:
$ npm install --save-dev babel-core
然後在node.js中,你可以呼叫這個函式:
require("babel-core").transform(ES5Code, options);
ES6總結
這裡還有許多ES6的其它特性你可能會使用到,排名不分先後:
1、全新的Math, Number, String, Array 和 Object 方法
2、二進位制和八進位制資料型別
3、預設引數不定引數擴充套件運算子
4、Symbols符號
5、tail呼叫
6、Generators (生成器)
7、New data structures like Map and Set(新的資料構造對像MAP和set)
參考文獻:
ES6 Cheatsheet (FREE PDF)
http://webapplog.com/ES6/comment-page-1/
Understanding ECMAScript 6 by Nicolas Zakas book
http://ES6-features.org/#DateTimeFormatting
IIFE:立刻執行的函式表示式
© 著作權歸作者所有
寫了 88536 字,被 877 人關注,獲得了 1017 個喜歡
普普通通的猿 極客教程網: https://www.geekjc.com 專注web開發,react,react-native.
作者:極客教程
連結:http://www.jianshu.com/p/53fe8b56cfb0
來源:簡書
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。