Node.js 全棧開發(二)——ES 201x 新語法的使用之基礎篇

在講 ES 2015 新語法以前,先來講一下爲何叫 ES。JavaScript 是這門語言的名稱,它有一個爲它制定標準化的組織 European Computer Manufacturers Association,直譯就是歐洲計算機制造商協會。這個 ECMA 制定的 JavaScript 的實現標準,被稱爲 ECMAScript,不一樣組織寫出來的 JavaScript 語言都要遵照這個 ECMAScript 標準,因此就簡寫爲 ES+版本號。css

這套 ES 標準在2015年以前最高的版本是5.1,也是惟一一個須要你們注意的版本:儘管各個流瀏覽器實現的 ES 新語法都有差別,但5.1版本是目前各大主流瀏覽器都支持的。這裏再介紹一下傳說中的 Babel.js 項目,它的目的很簡單,把新語法翻譯成老標準的語法。最主要的應用,就是把你寫的 ES 201x 的語法翻譯成 ES5.1,這樣各個瀏覽器都是支持的。前端

在2015年的時候,ES6 正式發佈,也很天然按照年份被稱爲 ES 2015。以後 ES 每一年都發佈一個版本,今年也就是2018年的草案也已經在年初發布了,從6開始今年該到版本9了可是很差記,因此你們都喜歡用 201x 來稱呼。雖然語法是歸在不一樣版本內的,可是各家 JS 的實現進度不一樣。你問一個語法具體是哪一個版本實現的,估計10我的裏有9個說不清楚,反正不是5.1的語法,因此你們也不區分了,直接都叫 ES 201x。jquery

已經出來了好幾年了,因此各類介紹的文章也很全面,我就不復制粘貼又臭又長了。在這裏向你們推薦幾個學習語法的英文網站,我就是從 babel 和 es6-features.org 這兩個網站學習的:webpack

https://babeljs.io/learn-es2015/es6

http://es6-features.org/web

https://css-tricks.com/lets-learn-es2015/ajax

中文的話,能夠看這個網站:redux

http://es6.ruanyifeng.com後端

另外呢,MDN( https://developer.mozilla.org ) 上對於這些語法的介紹是很全面的,中文英文也都有。數組

 

那麼接下來呢,我打算講一講這些新語法都解決了哪些問題,你應該怎麼使用它,這是通常介紹語法的文章不會介紹的。提早說明一下,我我的平時都在用 airbnb 的代碼風格,因此這些代碼都會延用它家的風格來寫。

1、const 與 let

首先要說的是,因爲 var 的問題不少,新語法中永遠不要用 var。它有的主要問題做用域是整個函數(function)而不是語法塊(block),致使的最大問題是會讓 closure 出現「bug」。並且這個「bug」還很經典,出如今許多著名語言中,其中也包括了

腳本界的老二 Python。構造這個 bug 的方法很簡單:

1 {
2   const funcs = [];
3   for (var i = 0; i < 5; i++) {
4     funcs.push(() => i);
5   }
6   funcs.map(fn => fn());
7 }

把上面的代碼粘貼到瀏覽器的 console 裏面,結果是5個5,而不是 [0, 1, 2, 3, 4],驚不驚喜,意不意外?雖然把上面的 var 換成 let 就成功的解決了這個問題,但按照如今 JS 傾側 FP 而不鼓勵使用 for 的趨勢,下面的方法纔是正確的使用姿式:

1 import { times } from 'lodash';
2 
3 const funcs = times(5, i => () => i);

lodash 是一個著名並且很是流行的 JS 庫,之後會有專門的文章介紹它。下面再給出其它語言生成這個 clusure 數組的正確投資,用 Python 舉例:

1 funcs = []
2 for i in range(5):
3   funcs.append((lambda x: lambda: x)(i))
4 [fn() for fn in funcs]

再嵌一層函數來返回須要生成函數的函數,而後再把參數傳過去。

那麼 const 呢,我在另一個扯一扯編譯語言的系列中已經提過,能用 const 就不要用 let。若是你使用了 eslint 的話,只賦值過一次的 let 變量會被提示應該換成 const。

總結下來,就是用 const 代替 var,const 實在解決不了的狀況,再用 let。不要以爲 const 多敲倆字母就不愛用,早幾年還能看到 let 滿天飛沒有 const 的項目,如今一個項目裏 let 出現的少才說明做者的水平高。一旦用了 var 你就是菜B一個,因此千萬不要用。

2、=> 箭頭函數(Arrow Function)

簡單來說是 function () {} 的簡寫形式,括號和參數列表寫在 => 前面,大括號和函數體寫在 => 後面,可是有3個很是重要的區別:

  1. function 的形式有兩組重要的變量,一個是 arguments,主要表明一個包含全部實參的數組,另一組是對象的上下文環境,主要包括 this、super。箭頭函數自己是沒有 this、super、arguments 這幾個變量的。
  2. 若是箭頭函數的函數體只返回一個表達式,也就是 () => { return EXPRESSION; },能夠省略 { return },也就變成了 () => EXPRESSION
  3. 當箭頭函數的參數只有一個時,能夠省略參數兩邊的括號。上面那段代碼中,就是由於外層的函數只有一個參數,我把 (i) => () => i 簡寫成了上面的形式。

最後一點並不重要,可是 airbnb 的代碼風格要求在只有一個參數時不使用括號,因此我在這裏專門提到了,但前面兩點都有值得說的地方。

第一條中再也不帶 this 等上下文變量,是爲了解決以前經常被詬病的搞不清當前 this 是啥的問題。JS 的對象模型是非主流的 prototype(原型)模型,在調用對象函數時,實際上使用的是相似 func.apply(this, arguments) 或者 func.call(this, ...arguments) 來實現的。因此當對象成員函數裏面又套了一層 function 的時候,因爲在內層函數聲明的時候 this 並無關聯任何上下文變量,而致使在內層函數中 this 使用時並非該對象,常常會致使試圖調用 undefined 的成員函數的問題。並且由於這個模型實在是太非主流了,因此你們常常會忘掉甚至搞不清。因此這個語法在很大程度上就是爲了解決 this 的問題。

第二條也會帶來一個問題,不少時候咱們想返回一個 Object,好比 { foo: 123, bar: 'baz' },可是 {} 這個東西又是函數體。很遺憾編譯器沒那麼聰明,當你寫 () => { foo: 123, bar: 'baz' } 的時候,會報語法錯誤。解決的辦法也很簡單,() 雖然套在表達式的外面它仍是一個表達式,因此 () => ({ foo: 123, bar: 'baz' }) 這種寫法就沒問題了。在 FP 流行的今天,這個技巧的使用真的是十分常見的,因此請養成想要返回 Object 時,直接先敲 ({}) 的習慣。

3、模板字符串(Template String)

Babel 的文檔裏面說,「This is similar to string interpolation features in Perl, Python and more.」,然而我並不以爲它跟 string interpolation 有什麼本質上的不一樣。這裏介紹一個技巧,若是你想 google 其它語言的這個語法的話,好比 Kotlin,那麼你應該用「string interpolation kotlin」做關鍵字,搜 template 可能不必定是你想要的結果,但 interpolation 必定能搜到。

這個語法自己已是如今語言的標配了,用標準鍵盤左上角的 `` 來包裹字符,能夠跨行,裏面所有的 ${EXPRESSION} 都會變成 EXPRESSION.toString() 插入到字符串中。

可是 JS 的這個語法還有一個神奇的用法,廢話很少說直接上代碼:

1 function test() { return JSON.stringify(arguments); }
2 test`foo${123}bar${456+789}baz`

你將會看到這樣的結果:{"0":["foo","bar","baz"],"1":123,"2":1245} 。第一個參數是正常的字符串部分,按照插入表達式的地方給切開了,剩下的參數則是其它表達式的值。雖然你不太可能會有機會須要用這語法來實現本身的庫的功能,但仍是有挺大的機會碰到第三方庫提供這樣的「語法支持」,好比 React 社區一些 CSS 庫。當你看到的時候,就不會以爲奇怪,到底人家的庫是怎麼寫的了。

4、模塊(Module)

做爲一門現代語言,沒有模塊化的設計是不可能達到工程級的使用的。過去咱們在使用 JS 的時候,都是在 HTML 裏導入 JavaScript 庫好比 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>。但這麼作會帶來一個問題就是可能會污染全局變量,一個現實的結果就是,假若有兩個庫都用了同一個全局變量名,那麼你就只能很當心的在引用兩個庫的中間插入一段代碼,重命名其中一個全局變量的名稱。另一個問題是,當一個庫須要使用另一個庫的時候,必須嚴格遵照必定的順序。

模塊化以後,帶來了兩個好處,一個是能夠自由的在本模塊中自由的命名,另外一個是使用 webpack 等工具打包時,能夠只打包使用到的代碼,從而減少須要發佈的 JS 文件大小,節省網絡傳輸時間加快頁面加載速度。

遺憾的是,因爲 JS 的模塊化並無統一的標準,致使出現了各類不一樣的加載方式。不過因爲 webpack 和 babel 的存在,在寫前端代碼時,你只要使用 export/import 這一套語法就夠了。但若是寫 Node 代碼,而你又不想使用 Babel 的話,那就得注意一下,因爲打包方式不一樣,一些在導入 default 時會要求 require(XXX).default,好比 redux-thunk。不過這種狀況通常也都是前端庫的代碼,若是純後端的話應該也不太須要擔憂。

5、二進制與八進制數字(Binary & Octal Literals)

這個語法也挺簡單的,跟16進制相似,0b 或者 0B 是2進制的前綴,用字母 O 替換 X 就是8進制的前綴。可是有一點須要注意的地方,你本身寫代碼的時候用用能夠,可是不要期望 parseInt 能夠像對十六進制同樣起做用。而像 isNaN、Number 之類的,跟瀏覽器自己的支持也有關,就算你上了 polyfill 也不必定會支持。固然你們會用這個語法的機率也不大。

6、其餘

關於 Symbol(符號)、Set、Map、WeekSet、WeekMap,我的感受不使用其實影響也不大,並且 polyfill 也不能作到徹底支持,作前端就不要考慮了。for ... of 的語法意義也不大,畢竟如今主流已經不推薦寫 for 了。iterator 自己沒有 Generator 好用,polyfill 支持也有限,因此也沒啥意義。剩下的 API 變化也沒什麼值得說的,前端也只要注意加個 babel-polyfill 之類的就夠了。

Proxy、Reflect、Decorator 算是 meta-programming 的內容,須要讀個人文章想來水平還不到有機會寫神奇功能的水平。若是想實現一些 fancy 的功能,這幾個東西仍是頗有用的。舉個例子,好比你想監視(observe)對象成員值的變化,老的作法你就得跑過去,獲取這個對象當前全部的屬性,而後再都給封裝一遍,就算這樣若是人家再加了個新成員變量你仍是沒辦法知道。上了 Proxy 你就不用那麼麻煩了,全部的操做都會在你的 proxy handler 裏面過一遍,實現起來就簡單多了。

 

其它的語法,Promise、async/await、Generator 會在異步裏面講,函數的變化、class、Rest/Spread、Destructing 相關性比較高也會放在同一個章節裏面講。

相關文章
相關標籤/搜索