儘管我們在實際開發中,想要使用ES6還是必須使用babel編譯之後才能使用,但是ES6仍然已經非常普及了,可以說是大多數聽說過前端的朋友都已經知道ES6,並且大多數人已經開始在使用ES6來進行學習和工作。
ES6徹底改變了前端的編碼風格,可是說對於前端的影響非常巨大。但是值得高興的是,如果你熟悉ES5,學習ES6並不需要花費太多的時間就可以掌握,因為常用的基礎語法並不多,我們花少量的時間,就可以開始自己的ES6之旅了。
這篇文章不會詳細的告訴你ES6的每一個細節知識,只會根據我自己的開發經驗,將我在實際開發中常常用到的知識點分享給大家,給大家學習ES6一個方向的指引。否則很多同學也不知道自己需要掌握那些ES6的知識,也不知道這些知識需要掌握到什麼程度,ES6大家都在說還算簡單,這也造成了許多人的更加迷茫,因此這篇文章就算是一個劃重點吧,掌握這些,就可以輕輕鬆鬆的去學習react/vue了。
在學習之前,推薦大家使用babel官方提供的線上編譯工具,編寫自己的demo,會在右側實時顯示出編譯之後的程式碼,以供參考學習 http://babeljs.io/repl/
一、新的變數宣告方式 let/const
與var不同,新的變數宣告方式帶來了一些不一樣的特性,其中最重要的兩個特性就是提供了塊級作用域與不再具備變數提升。
通過2個簡單的例子來說明這兩點。
1 2 3 4 5 |
{ let a = 20; } console.log(a); // a is not defined |
而這個簡單的例子,會被編譯為:
1 2 3 4 5 |
{ let _a = 20; } console.log(a); // a is not defined |
1 2 3 4 5 6 7 |
// ES5 console.log(a); // undefined var a = 20; // ES6 console.log(a); // a is not defined let a = 20; |
當然,如果你的程式碼編譯成為了ES5之後,仍然會存在變數提升,因此這一點只需要我們記住即可。我們在實際使用中,也需要儘量避免使用變數提升的特性帶來的負面影響。對於變數提升的濫用,只存在與面試題中。
使用ES6,我們需要全面使用let/const替換var,那麼什麼時候用let,什麼時候用const就成為了一個大家要熟練區分的一個知識點。
我們常常使用let來宣告一個值會被改變的變數,而使用const來宣告一個值不會被改變的變數。
當值為基礎資料型別時,那麼這裡的值,就是指值本身。
而當值對應的為引用資料型別時,那麼我這裡說的值,則表示指向該物件的引用。這裡需要注意,正因為該值為一個引用,重要保證引用不變就可以,我們仍然可以改變該引用所指向的物件。
當我們試圖改變const宣告的變數時,則會報錯。
寫幾個例子,大家可以仔細揣摩一下:
1 2 |
let a = null; a = 20; |
1 2 3 4 5 6 7 8 |
const obDev = { a: 20, b: 30 } obDev.a = 30; console.log(obDev); // Object {a: 30, b: 30} |
1 2 3 |
const fn = function() {} const a = obDev.a; ... ... |
只要抓住上面我說的特性,那麼在使用let/const時就會顯得遊刃有餘。
根據我自己的經驗,使用const的場景要比使用let的場景多很多。
二、 箭頭函式的使用
之前我說ES6顛覆了js的編碼習慣,箭頭函式的使用佔了很大一部分。
首先是寫法上的不同:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// es5 var fn = function(a, b) { return a + b; } // es6 箭頭函式寫法,當函式直接被return時 const fn = (a, b) => a + b; // es5 var foo = function() { var a = 20; var b = 30; return a + b; } // es6 const foo = () => { const a = 20; const b = 30; return a + b; } |
箭頭函式可以替換函式表示式,但是不能替換函式宣告
其次還有一個至關重要的一點,那就是箭頭函式中,沒有this。如果你在箭頭函式中使用了this,那麼該this一定就是外層的this。
也正是因為箭頭函式中沒有this,因此我們也就無從談起用call/apply/bind來改變this指向。記住這個特性,能讓你在react元件之間傳值時少走無數彎路。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
var person = { name: 'tom', getName: function() { return this.name; } } // 我們試圖用ES6的寫法來重構上面的物件 const person = { name: 'tom', getName: () => this.name } // 但是編譯結果卻是 var person = { name: 'tom', getName: function getName() { return undefined.name; } }; |
在ES6中,會預設採用嚴格模式,因此this也不會自動指向window物件了,而箭頭函式本身並沒有this,因此this就只能是undefined,這一點,在使用的時候,一定要慎重慎重再慎重,不然踩了坑你都不知道自己錯在哪!這種情況,如果你還想用this,就不用使用箭頭函式的寫法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// 可以稍做改動 const person = { name: 'tom', getName: function() { return setTimeout(() => this.name, 1000); } } // 編譯之後變成 var person = { name: 'tom', getName: function getName() { var _this = this; // 使用了我們在es5時常用的方式儲存this引用 return setTimeout(function () { return _this.name; }, 1000); } }; |
先記住箭頭函式的寫法,並留意箭頭函式中關於this的特殊性,更過實踐與注意事項我們在封裝react元件時再慢慢來感受。
三、模板字串
模板字串是為了解決使用+號拼接字串的不便利而出現的。它的功能非常強大,但是我們大多數時候使用它則非常簡單。看一個例子大家就明白怎麼使用了。
1 2 3 4 5 6 7 8 9 |
// es6 const a = 20; const b = 30; const string = `${a}+${b}=${a+b}`; // es5 var a = 20; var b = 30; var string = a + "+" + b + "=" + (a + b); |
使用 整個字串包裹起來,而在其中使用 ${} 來包裹一個變數或者一個表示式。
當然模板字串還支援換行等強大的功能,更多的大家可通過參考資料進一步學習。
四、 解析結構
解析結構是一種全新的寫法,我們只需要使用一個例子,大家就能夠明白解析結構到底是怎麼一回事兒。
1 2 3 4 5 6 7 |
// 首先有這麼一個物件 const props = { className: 'tiger-button', loading: false, clicked: true, disabled: 'disabled' } |
當我們想要取得其中的2個值:loading與clicked時:
1 2 3 4 5 6 7 8 9 |
// es5 var loading = props.loading; var clicked = props.clicked; // es6 const { loading, clicked } = props; // 給一個預設值,當props物件中找不到loading時,loading就等於該預設值 const { loading = false, clicked } = props; |
是不是簡單了許多?正是由於解析結構大大減少了程式碼量,因此它大受歡迎,在很多程式碼中它的影子隨處可見。
1 2 3 4 5 6 7 8 9 10 11 12 |
// 比如 // section1 import React, { Component } from 'react'; // section2 export { default } from './Button'; // section3 const { click, loading } = this.props; const { isCheck } = this.state; // more 任何獲取物件屬性值的場景都可以使用解析結構來減少我們的程式碼量 |
另外,陣列也有屬於自己的解析結構。
1 2 3 4 5 6 7 8 9 |
// es6 const arr = [1, 2, 3]; const [a, b, c] = arr; // es5 var arr = [1, 2, 3]; var a = arr[0]; var b = arr[1]; var c = arr[2]; |
陣列以序列號一一對應,這是一個有序的對應關係。
而物件根據屬性名一一對應,這是一個無序的對應關係。
根據這個特性,使用解析結構從物件中獲取屬性值更加具有可用性。
五、 函式預設引數
之前我們不能直接為函式指定預設引數,因此很多時候為了保證傳入的引數具備一個預設值,我們常常使用如下的方法:
1 2 3 4 5 6 7 |
function add(x, y) { var x = x || 20; var y = y || 30; return x + y; } console.log(add()); // 50 |
這種方式並不是沒有缺點,比如當我傳入一個x值為false,這個時候任然會取到預設值,就不是我們的本意了。
來看看ES6的預設值寫法:
1 2 3 4 5 |
function add(x = 20, y = 30) { return x + y; } console.log(add()); |
在實際開發中給引數新增適當的預設值,可以讓我們堆函式的引數型別有一個直觀的認知。
1 2 3 4 5 6 7 8 9 |
const ButtonGroupProps = { size: 'normal', className: 'xxxx-button-group', borderColor: '#333' } export default function ButtonGroup(props = ButtonGroupProps) { ... ... } |
六、 展開運算子
在ES6中用...
來表示展開運算子,它可以將陣列方法或者物件進行展開。先來看一個例子它是如何使用的。
1 2 3 4 |
const arr1 = [1, 2, 3]; const arr2 = [...arr1, 10, 20, 30]; // 這樣,arr2 就變成了[1, 2, 3, 10, 20, 30]; |
當然,展開物件資料也是可以得到類似的結果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
const obj1 = { a: 1, b: 2, c: 3 } const obj2 = { ...obj1, d: 4, e: 5, f: 6 } // 結果類似於 const obj2 = Object.assign({}, obj1, {d: 4}) |
展開運算子還常常運用在解析結構之中,例如我們在Raect封裝元件的時候常常不確定props到底還有多少資料會傳進來,就會利用展開運算子來處理剩餘的資料。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// 這種方式在react中十分常用 const props = { size: 1, src: 'xxxx', mode: 'si' } const { size, ...others } = props; console.log(others) // 然後再利用暫開運算子傳遞給下一個元素,再以後封裝react元件時會大量使用到這種方式,正在學習react的同學一定要搞懂這種使用方式 <button></button> |
展開運算子還用在函式的引數中,來表示函式的不定參。只有放在最後才能作為函式的不定參,否則會報錯。
1 2 3 4 5 6 |
// 所有引數之和 const add = (a, b, ...more) => { return more.reduce((m, n) => m + n) + a + b } console.log(add(1, 23, 1, 2, 3, 4, 5)) // 39 |
展開運算子的運用可以大大提高我們的程式碼效率,但是在剛開始使用的時候比較繞腦,掌握好了用起來還是非常爽的,記住這些使用場景,平時在用的時候可以刻意多運用就行了。
七、 類 Class
八、 模組 Modules
深入學習ES6推薦 http://es6.ruanyifeng.com/
暫時先寫到這裡,太困了 ~ ~,更多的明天下班繼續補充