ECMAScript 8都發布了,你還沒有用上ECMAScript 6?

2018-02-28 17:06:59 ortotra

ES8已經與17年6月底發布,而很多的前端開發者還沒有開始用上ES6。本文聊一聊怎麽快速入門ES6,并将ES6的語法應用到實戰項目中。

閱讀全文大約需要15分鍾。

文中以 ES 表示 ECMAScript。

今年六月底,TC39發布新一版的ES 8(ES 2017),自從ES6在15年發布之後,每一年TC39都會發布新一版的ES語言标準。

我了解的前端開發者中,還有很多人沒有用上ES6,有的人是(shì)覺得ES5用的挺好的,懶得去(qù)學ES6,有的人是(shì)有想學ES6的決心,但(dàn)是(shì)苦于沒有合适的機會(項目)去(qù)實戰練習。

如果你用過React,Vue或Nodejs等,那你多多少少都會使用到一些ES6語法的。

ES8中的新特性,浏覽器廠商和語法轉換器還需要一段來實現(xiàn),不如我們還是(shì)先聊聊怎麽在你的項目中用上ES6吧。

什麽是(shì)ES6?它和ES5有什麽區别?

我們常說的JavaScript是(shì)指ES3和ES5,ES6是(shì)ECMAScript 6 的縮寫。

對于經常寫原生JavaScript的前端開發者來說,對ES5中的語法肯定比較熟悉,比如數組中的一些方法forEach,map,filter,some,every,indexOf,lastIndexOf,reduce,reduceRight ……,以及對象(Object)和函數(Function)都拓展了很多方法,這裏不多贅叙。

ES6給前端開發者帶來了很多的新的特性,可以更簡單的實現(xiàn)更複雜(zá)的操作,很大的提高開發效率,提高代碼的整潔性。

ES6中的新特性有很多,列一些比較常用的特性:

Block-Scoped Constructs Let and Const(塊作用域構造Let and Const)

Default Parameters(默認參數)

Template Literals (模闆字符串)

Multi-line Strings (多行字符串)

Arrow Functions (箭頭函數)

Enhanced Object Literals (增強的對象文本)

Promises

Classes(類)

Modules(模塊)

Destructuring Assignment (解構賦值)

下(xià)面介紹下(xià)這些常用的ES6特性。

Block-Scoped Constructs Let and Const(塊作用域構造Let and Const)

ES6提供了兩個新的聲明變量的關鍵字:let和const。而let和const要和塊級作用域結合才能發揮其優勢。

什麽是(shì)塊級作用域?

塊級作用域的表示一對大括号{}包圍的區域是(shì)一個獨立的作用域,在這個作用域内用let聲明的變量a,隻能在這個作用域内被訪問到,在這對大括号外面是(shì)訪問不到a的。

當然,在塊級作用域中還可以聲明函數,該函數也是(shì)隻能作用域内部才能被訪問到。所以,在if、else、for甚至是(shì)一對單獨的{},都是(shì)一個塊級作用域。

在ES6之前,是(shì)沒有塊級作用域的概念的,隻有全局作用域和函數作用域兩種,并且,用var聲明的變量和用function聲明的函數會被提前到作用域的頂部,這也就是(shì)我們常說的聲明提前。

用let聲明的變量是(shì)存在于距離(lí)聲明語句最近的一個作用域(全局作用域、函數作用域或塊級作用域)内的,在聲明的時候,可選的将其初始化成一個值。

語法如下(xià):


let var1 [= value1] [, var2 [= value2 ] ] [, ..., varN [= valueN]] ;

這一點與var的聲明不同,用var聲明的變量是(shì)屬于離(lí)他最近的一個全局作用域或函數作用域中,且聲明會被提前。在塊級作用域中,var的聲明與在全局作用域和函數作用域中是(shì)一樣的。


塊級作用域和let聲明變量,解決了使用var一些痛點,相(xiàng)當于用let聲明的變量不會被提前到作用域頂部。


有一點需要注意,let也是(shì)聲明提前,但(dàn)是(shì)let聲明變量的語句必須在使用該變量語句之前,在聲明之前引用會報錯該變量未被聲明,且let不允許重複聲明相(xiàng)同名稱的變量,否則會報錯。我們看下(xià)例子:


{

  var hello = 'Hello';

  let world = 'World';

}

console.log(hello);

console.log(world);

在Chrome浏覽器的控制台(最新版本的Chrome已支持一部分ES6語法)執行一下(xià),會發現(xiàn)有報錯,見(jiàn)下(xià)圖。constconst聲明與let基本相(xiàng)同,它也是(shì)存在于塊級作用域内。

有一點區别就是(shì)const聲明的是(shì)常量,即不可被重新賦值改變原值。需要注意,const在聲明常量的時候,必須同時給常量初始化賦值。如果隻聲明,不初始化值的話(huà),會報錯。見(jiàn)下(xià)面代碼。

const MAX;

// Uncaught SyntaxError: Missing initializer in const declaration

聲明變量的方法

在ES5中,可以通過var和function這兩種方法來聲明變量。


而在ES6中,除了增加了let和const兩種聲明方式,還有接下(xià)來要介紹的import和class的聲明方式。

Default Parameters(默認參數)

默認參數是(shì)ES6中對函數拓展的一個特性,可以直接爲函數的參數設置默認值,當某一參數設置了默認值時,如果調用函數的時候沒有傳該參數,則該參數的值爲默認值,如果傳了該參數,則該參數的值爲傳遞的參數值。

在ES6之前,我們可以通過手動的方式,爲函數的參數設置默認值,代碼如下(xià):

function sign (x) {

  if (typeof x === 'undefined') {

    x = 'default'

  }

  console.log(x)

}

sign('new sign')    // new sign

sign()              // default

将上述代碼換成ES6模式,可以這樣寫:


function sign (x = 'default') {

  console.log(x)    

}

sign('new sign')    // new sign

sign()              // default

Template Literals (模闆字符串)


ES6提供了模闆字符串的特性,模闆字符串是(shì)使用反引号(`)和${}實現(xiàn)字符串的拼接,字符串中可以嵌入變量。

在ES6之前,我們一般這樣輸出模闆:

var name = 'Henry';

var welcome = 'Hello, ' + name + '!';

console.log(welcome);   // Hello, Henry!

在ES6中,模闆字符串可以這樣拼接字符串:

let name = 'Henry';

let welcome = `Hello, ${ name }!`;

console.log(welcome);   // Hello, Henry

模闆字符串的計算規則是(shì)在兩個反引号之間将字符串拼接到一起,如果反引号之間含有${},則會計算這對大括号内的值,大括号裏面可以是(shì)任意的JavaScript表達式,可以進行運算和引用對象屬性。

let a = 3;

let number = `$ {a + 2 }`;

console.log(`${ number }`);    // 5


let b = { c: 2, d: 4 };

console.log(`${ b.c * b.d }`) ;     // 8

Multi-line Strings (多行字符串)


多行字符串是(shì)模闆字符串的拓展,它跟模闆字符串是(shì)同樣的解析方式,不同的是(shì),它可以拼接多行的字符串,且拼接的字符串中會保留所有的空格和縮進。

如果需要用字符串來拼接DOM樹(shù)結構時,可以這樣寫:

let titleValue = 'This is a title';

let htmlStr = `

 


     

${ titleValue }


     

This is a paragraph.

 

`;

上述代碼中,能看到JavaScript代碼和僞html代碼的結合,完全可以将模闆字符串的多行字符串封裝成一個頁面模闆工具,絕對是(shì)輕量高效的。

還有,這種書(shū)寫方式是(shì)不是(shì)很眼熟,跟React的JSX是(shì)不是(shì)很像雙胞胎啊。

Arrow Functions (箭頭函數)

在ES6中,可以使用箭頭(=>)來聲明一個函數,稱作箭頭函數。

ES5中聲明一個函數,可以這樣寫:

var func = function (a) {

  return a + 2;

}

将這個函數換成 箭頭函數:

let func = a => a + 2;

如果函數有多個參數,需要用括号包含所有參數,隻有一個參數的時候,可以省略括号,如果沒有設置參數,也必須有括号。示例如下(xià):


let func1 = (arg1, arg2, arg3) => {

  return arg1 + arg2 + arg3;

}


let func2 = arg => {

  console.log(arg)

}

let func3 = () => {

  console.log(`This is an arrow function.`)

}

需要注意的是(shì),箭頭函數沒有自己的this,如果在箭頭函數内部使用this,那樣這個this是(shì)箭頭函數外部的this,也是(shì)因爲箭頭函數沒有this,所以,箭頭函數不能用作構造函數。如果用箭頭函數來寫回調函數時,就不用再将外部this保存起來了。

// ES5

function foo() {

  var _this = this;

    

  setTimeout(function() {

    console.log('id:', _this.id);        

  }, 200)

}

// ES6

function foo() {

  setTimeout(() => {

    console.log(`id:${ this.id }`)        

  }, 200)

}

Enhanced Object Literals (增強的對象文本)


在ES6,對象字面值擴展支持在創建時設置原型,簡寫foo:foo分配,定義方法,加工父函數(super calls),計算屬性名(動态)。總之,這些也帶來了對象字面值和類聲明緊密聯系起來,讓基于對象的設計得益于一些同樣的便利。


var obj = {

  // __proto__ 原型

  __proto__: theProtoObj,

  // Shorthand for ‘handler: handler’  簡寫

  handler,

  // Methods

  toString() {

    // Super calls     繼承

    return "d " + super.toString();

  },

  // Computed (dynamic) property names 計算屬性名

  ['prop_' + (() => 42)()]: 'name'

};

Promises

Promise是(shì)異步編程的一種解決方案,它是(shì)一個對象,且隻要開始就會一直進行下(xià)去(qù),直到成功或者失敗。就像它的字面意思諾言一樣,一個諾言,隻要被許下(xià),就隻有兩種解決:成功或失敗。

Promise的結果是(shì)由異步操作的結果決定的,且一旦結果形成,便不可再被改變,任何時候都得到同樣的結果。

需要注意的是(shì):Promise被新建後,便無法被取消,會執行下(xià)去(qù),直到出現(xiàn)結果;如果不設置回調,Promise内部抛出的異常,不會反應到外部。