ECMAScript6新特性簡介
原文:http://blog.gejiawen.com/2015/07/28/es6-new-feature/
ES6(ECMAScript 6)終於在2015年6月正式釋出了。距離上一次正式公開的ES5(於2009年釋出的)已經相距了不短的時間了。其實在ES6正式釋出之前的一段時間內,ECMA組織已經不再向ES6中新增新特性了,所以其實在ES6正式釋出之前,業界已經有許多對ES6的相關實踐了。比如阮一峰的ECMAScript 6入門其實就是早於ES6的正式釋出時間的。
本文將主要基於lukehoban/es6features,參考眾多的部落格文章資料,對新出的ES6中新增的特性做一個簡介。後續本系列將會產出針對ES6不同特性的文章。
ES6新特性列表
下面的表格給出了ES6包含的所有特性,
新增特性 | 關鍵詞 | 用法 | 描述 |
---|---|---|---|
箭頭操作符 | Arrows | v => console.log(v) |
類似於部分強型別語言中的lambda表示式 |
類的支援 | Classes | - | 原生支援類,讓javascript的OOP編碼更加地道 |
增強的物件字面量 | enhanced object literals | - | 增強物件字面量 |
字串模板 | template strings | ${num} |
原生支援字串模板,不再需要第三方庫的支援 |
解構賦值 | destructuring | [x, y] = ['hello',
'world'] |
使用過python的話,你應該很熟悉這個語法 |
函式引數擴充套件 | default, rest, spread | - | 函式引數可以使用預設值、不定引數以及拓展引數了 |
let、const | let、const | - | javascript中可以使用塊級作用域和宣告常量了 |
for…of遍歷 | for…of | for (v of someArray)
{ ... } |
又多了一種折騰陣列、Map等資料結構的方法了 |
迭代器和生成器 | iterators, generator, iterables | - | ES6較為難以理解的新東西,後面會有相關文章 |
Unicode | unicode | - | 原生的unicode更加完美的支援 |
模組和模組載入 | modules, modules loader | - | ES6中開始支援原生模組化啦 |
map, set, weakmap, weakset | - | - | 新的資料結構 |
監控代理 | proxies | - | 我們可以監聽物件發生了哪些事,並可以自定義對應的操作 |
Symbols | - | - | 我們可以使用symbol來建立一個不同尋常的key |
Promises | - | - | 這傢伙經常在討論非同步處理流程時被提到 |
新的API | math, number, string, array, object | - | 原生的功能性API就是方便些 |
內建物件可以被繼承 | subclassable built-ins | - | 可以基於內建物件,比如Array,來生成一個類 |
二進位制、八進位制字面量 | - | - | 可以直接在es6中使用二進位制或者八進位制字面量了 |
Reflect API | - | - | 反射API? |
尾呼叫 | tail calls | - | ES6中會自動幫你做一些尾遞迴方面的優化 |
ok,上面就是es6中涉及到的所有的新增特性。下面我們針對每一個topic,舉一個sample example加以說明,不過並不會深入闡述。
箭頭操作符
何為箭頭操作符?其實箭頭操作符其實就是使用=>
語法來代替函式。如果你熟悉C#或者Java之類的強型別語音,你應該知道lambda語法,其實箭頭操作符做的事情跟lambda表示式有異曲同工之妙。具體的用法看下面的例子,
123456789 |
var arr = [1, 2, 3];// 傳統寫法arr.forEach(function (v) { console.log(v);});// 使用箭頭操作符arr.forEach( v => console.log(v)); |
在傳統寫法中,我們需要寫一個匿名的函式,然後給這個函式傳入引數,在函式體中對此引數做相關處理。而使用箭頭操作符後,它簡化了函式的編寫(其實是不需要再寫匿名函數了)。
箭頭操作符的左側可以接收一個簡單的引數,也可以使用一個引數列表。右側進行具體的操作或者是返回值。下面的示例展示了箭頭操作符更一般的用法,
123456789101112131415161718 |
// 在表示式中使用var odds = evens.map(v => v + 1);var nums = evens.map((v, i) => v + i);var pairs = evens.map(v => ({even: v, odd: v + 1}))// 在申明中使用nums.forEach(v => { if (v % 5 === 0) fives.push(v);});// 使用this指標var bob = { _name: "Bob", _friends: [], printFriends() { this._friends.forEach(f => consol.log(this._name + " knows " + f)); }} |
類的原生支援
ES6中提供了類的原生支援,引入了class
關鍵字,其實它是一種實現OOP程式設計思想的語法糖。它是基於原型鏈的。
其實javascript本身就是面向物件的語音,只不過沒有Java之類的語言那麼學院派,它更加靈活。ES6中提供的類其實就是對原型模型的包裝。
ES6提供原生class
支援後,類方面的操作,比如類的建立、繼承等等更加直觀了。並且父類方法的呼叫、例項化、靜態方法和建構函式等OOP概念都更加形象化了。
我們來看一些示例,看在ES6中到底如何使用學院化的使用類,
1234567891011121314151617181920212223242526272829303132333435363738 |
// 類的定義class Animal { // ES6中的構造器,相當於建構函式 constructor(name) { this.name = name; } // 例項方法 sayName() { console.log('My Name is ' + this.name); }}// 類的繼承class Programmer extends Animal { constructor(name) { // 直接呼叫父類構造器進行初始化 super(name); } // 子類自己的例項方法 program() { console.log('I\'am coding...'); } // 靜態方法 static LEVEL() { console.log('LEVEL BAD!'); }}// 一些測試var doggy=new Animal('doggy'),larry=new Programmer('larry');doggy.sayName(); // ‘My name is doggy’larry.sayName(); // ‘My name is larry’larry.program(); // ‘I'm coding...’Programmer.LEVEL(); // ‘LEVEL BAD!’ |
可以看到,ES6中我們可以完全用Java中的思想來寫建立類、繼承類、例項方法、初始化等等。
物件字面量的增強
在ES6中,物件字面量被增強了,寫法更賤geek,同時可以在定義物件的時候做的事情更多了。比如,
- 可以在物件字面量裡面定義原型
- 定義方法可以不用
function
關鍵字了 - 更加方便的定義方法
- 直接呼叫原型鏈上層(父層)的方法
具體的我們看下面的示例程式碼,
12345678910111213141516171819202122 |
var human = { breathe() { console.log('breathing...'); }};function sleep() { console.log('sleeping...');}var worker = { __proto__: human, // 設定原型,相當於繼承human company: 'code', sleep, // 相當於 `sleep: sleep` work() { console.log('working...'); }};human.breathe(); // `breathing...`worker.sleep(); // `sleeping...`worker.work(); // `working...` |
字串模板
ES6中提供原生的字串模板支援。其語法很簡單使用使用反引號`來建立字串模板,字串模板中可以使用${placeholder}來生成佔位符。
如果你有使用後端模板的經驗,比如smarty
之類的,那麼你將對此不會太陌生。讓我們來看段示例,
12 |
var num = Math.random();console.log(`your random num is ${num}`); |
字串模板其實並不是很難的東西,相對比較容易理解。個人覺得其目前主要的使用場景就是改變了動態生成字串的方式,不再像以前那樣使用字串拼接的方式。
解構賦值
如果你熟悉python等語言,你對解構賦值的概念應該很瞭解。解構的含義簡單點就是自動解析陣列或者物件中值,解析出來之後一次賦值給一系列的變數。
利用這個特性,我們可以讓一個函式返回一個數組,然後利用解構賦值得到陣列中的每一個元素。讓我們來看一些例子。
1234567891011121314 |
function getVal() { return [1, 2];}var [x, y] = getValue();var [name, age] = ['larry', 26];console.log('x: ' + x + ', y: ' + y); // x: 1, y: 2console.log('name: ' + name + ', age: ' + age); // name: larry, age: 26// 交換兩個變數的值var [a, b] = [1, 2];[a, b] = [b, a];console.log('a: ' + a + ', b: ' + b); |
函式引數的擴充套件
ES6中對函式引數作了很大的擴充套件,包括
- 預設引數
- 不定引數
- 擴充套件引數
預設引數,即我們可以為函式的引數設定預設值了。可能你在某些js庫的原始碼經常會看到類似下面這樣的操作,
1234 |
function foo(name) { name = name || 'larry'; console.log(name);} |
上面的或操作其實就是為了給引數name
設定預設值。
而在ES6中,我們可以採用更加方便的方式,如下,
123456 |
function foo(name = 'larry') { console.log(name);}foo(); // 'larry'foo('gejiawen'); // 'gejiawen' |
不定引數的意思是,我們的函式接受的引數是不確定的,由具體的呼叫時決定到底會有幾個引數。其實在ES6之前的規範中我們大可以使用arguments
變數來達到不定引數的判斷,但是無疑這一方案過於複雜。
不定引數的用法是這樣的,我們在函式引數中使用...x
這樣的方式來代表所有的引數。其中x
的作用就是指代所有的不定引數集合(其實它就是一個數組)。讓我們來看個例子,
123456 |
function add(...x) { return x.reduce((m, n) => m + n);}console.log(add(1, 2, 3)); // 6console.log(add(1, 2, 3, 4, 5)); // 15 |
關於拓展引數,其實拓展引數其實一種語法糖,它允許傳遞一個數組(或者類陣列)作為函式的引數,而不需要apply
操作,函式內部可以自動將其當前不定引數解析,然後可以獲得每一個數組(類陣列)元素作為實際引數。看下面的示例,
12345 |
function foo(x, y, z) { return x + y + z;}console.log(foo(...[1, 2, 3])); // 6 |
新增let
和const
關鍵字
ES6中新增了兩個關鍵字,分別為let
和const
。
let
用於宣告物件,作用類似var
,但是let
宣告的變數擁有更狹隘的作用域,脫離特定的作用域後變數的生命週期就終結了。這將有效的避免javascript中由於隱式變數作用域提升而導致的各種bug,甚至是記憶體洩露等等問題。
const
用於宣告常量。
讓我們來看一些例子。
1234 |
for (let i = 0; i < 2; i++) { console.log(i); // 0, 1}console.log(i); // undefined, 嚴格模式下會報錯 |
for...of
遍歷
ES6中新增了一種遍歷陣列和物件的方法,叫做for...of
。他與for...in
用法相似。看下面的例子,
123456789 |
var arr = [1, 2, 3];for (let v of arr) { console.log(v); // 1,2,3}for (let i in arr) { console.log(arr[i]); // 1,2,3} |
從上面的示例程式碼中,我們可以看出,for...of
遍歷時提供的是value,而for...in
遍歷提供的是key。
迭代器和生成器
ES6中新增的迭代器和生成器的相關概念相對來說有點複雜,後面將會產出專門的文章針對這個topic進行闡述。
Promise
Promises是處理非同步操作的一種模式,之前在很多三方庫中有實現,比如jQuery的deferred
物件。當你發起一個非同步請求,並綁定了.when()
,.done()
等事件處理程式時,其實就是在應用promise模式。下面是一段示例程式碼,
123456789101112131415161718 |
//建立promisevar promise = new Promise(function(resolve, reject) { // 進行一些非同步或耗時操作 if ( /*如果成功 */ ) { resolve("Stuff worked!"); } else { reject(Error("It broke")); }});//繫結處理程式promise.then(function(result) { //promise成功的話會執行這裡 console.log(result); // "Stuff worked!"}, function(err) { //promise失敗會執行這裡 console.log(err); // Error: "It broke"}); |
關於promise更多的詳細內容,後面將會產出專門的文章針對這個topic進行闡述。
Unicode的支援
ES6中對Unicode的支援更加完善了,可以使用使用正則表示式的u
標記對unicode字串進行匹配。
12345678910111213141516 |
// same as ES5.1" |