參考博客: http://www.javashuo.com/article/p-wnodfuzt-r.htmljavascript
與var不一樣,新的變量聲明方式帶來了一些不同的特性,其中最重要的兩個特性就是提供了塊級做用域與再也不具有變量提高。html
經過2個簡單的例子來講明這兩點。前端
{
let a = 20; } console.log(a); // a is not defined
而這個簡單的例子,會被編譯爲:vue
{
let _a = 20; } console.log(a); // a is not defined
// ES5 console.log(a); // undefined var a = 20; // ES6 console.log(a); // a is not defined let a = 20;
固然,你的代碼編譯成爲了ES5以後,仍然會存在變量提高,所以這一點只須要咱們記住便可。在實際使用中,也須要儘可能避免使用變量提高的特性帶來的負面影響。只有在面試題中,纔會對變量提高不停的濫用。java
使用ES6,咱們須要全面使用let/const替換var,那麼何時用let,何時用const就成爲了一個你們要熟練區分的一個知識點。react
咱們經常使用let來聲明一個值會被改變的變量,而使用const來聲明一個值不會被改變的變量,也能夠稱之爲常量。es6
當值爲基礎數據類型時,那麼這裏的值,就是指值自己。
而當值對應的爲引用數據類型時,那麼我這裏說的值,則表示指向該對象的引用。這裏須要注意,正由於該值爲一個引用,只須要保證引用不變就能夠,咱們仍然能夠改變該引用所指向的對象。面試
當咱們試圖改變const聲明的變量時,則會報錯。編程
寫幾個例子,你們能夠仔細揣摩一下:數組
let a = null; a = 20;
const obDev = { a: 20, b: 30 } obDev.a = 30; console.log(obDev); // Object {a: 30, b: 30}
const fn = function() {} const a = obDev.a; ... ...
只要抓住上面我說的特性,那麼在使用let/const時就會顯得遊刃有餘。
根據我本身的經驗,使用const的場景要比使用let的場景多不少。
以前我說ES6顛覆了js的編碼習慣,箭頭函數的使用佔了很大一部分。
首先是寫法上的不一樣:
// 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組件之間傳值時少走無數彎路。
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,就不要用使用箭頭函數的寫法。
// 能夠稍作改動 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組件時再慢慢來感覺。
模板字符串是爲了解決使用+號拼接字符串的不便利而出現的。它的功能很是強大,可是咱們大多數時候使用它則很是簡單。看一個例子你們就明白怎麼使用了。
// 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);
使用 `` 將整個字符串包裹起來,而在其中使用 ${} 來包裹一個變量或者一個表達式。
固然模板字符串還支持換行等強大的功能,更多的你們可經過參考資料進一步學習。
解析結構是一種全新的寫法,咱們只須要使用一個例子,你們就可以明白解析結構究竟是怎麼一回事兒。
// 首先有這麼一個對象 const props = { className: 'tiger-button', loading: false, clicked: true, disabled: 'disabled' }
當咱們想要取得其中的2個值:loading與clicked時:
// es5 var loading = props.loading; var clicked = props.clicked; // es6 const { loading, clicked } = props; // 給一個默認值,當props對象中找不到loading時,loading就等於該默認值 const { loading = false, clicked } = props;
是否是簡單了許多?正是因爲解析結構大大減小了代碼量,所以它大受歡迎,在不少代碼中它的影子隨處可見。
// 好比 // section1 import React, { Component } from 'react'; // section2 export { default } from './Button'; // section3 const { click, loading } = this.props; const { isCheck } = this.state; // more 任何獲取對象屬性值的場景均可以使用解析結構來減小咱們的代碼量
另外,數組也有屬於本身的解析結構。
// 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];
數組以序列號一一對應,這是一個有序的對應關係。
而對象根據屬性名一一對應,這是一個無序的對應關係。
根據這個特性,使用解析結構從對象中獲取屬性值更加具備可用性。
以前咱們不能直接爲函數指定默認參數,所以不少時候爲了保證傳入的參數具有一個默認值,咱們經常使用以下的方法:
function add(x, y) { var x = x || 20; var y = y || 30; return x + y; } console.log(add()); // 50
這種方式並非沒有缺點,好比當我傳入一個x值爲false,這個時候任然會取到默認值,就不是咱們的本意了。
來看看ES6的默認值寫法:
function add(x = 20, y = 30) { return x + y; } console.log(add());
在實際開發中給參數添加適當的默認值,可讓咱們對函數的參數類型有一個直觀的認知。
const ButtonGroupProps = { size: 'normal', className: 'xxxx-button-group', borderColor: '#333' } export default function ButtonGroup(props = ButtonGroupProps) { ... ... }
在ES6中用...
來表示展開運算符,它能夠將數組方法或者對象進行展開。先來看一個例子它是如何使用的。
const arr1 = [1, 2, 3]; const arr2 = [...arr1, 10, 20, 30]; // 這樣,arr2 就變成了[1, 2, 3, 10, 20, 30];
固然,展開對象數據也是能夠獲得相似的結果
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到底還有多少數據會傳進來,就會利用展開運算符來處理剩餘的數據。
// 這種方式在react中十分經常使用 const props = { size: 1, src: 'xxxx', mode: 'si' } const { size, ...others } = props; console.log(others) // 而後再利用暫開運算符傳遞給下一個元素,再之後封裝react組件時會大量使用到這種方式,正在學習react的同窗必定要搞懂這種使用方式 <button {...others} size={size} />
展開運算符還用在函數的參數中,來表示函數的不定參。只有放在最後才能做爲函數的不定參,不然會報錯。
// 全部參數之和 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
展開運算符的運用能夠大大提升咱們的代碼效率,可是在剛開始使用的時候比較繞腦,掌握好了用起來仍是很是爽的,記住這些使用場景,平時在用的時候能夠刻意多運用就好了。
ES6針對對象字面量作了許多簡化語法的處理。
const name = 'Jane'; const age = 20 // es6 const person = { name, age } // es5 var person = { name: name, age: age };
那麼這種方式在任何地方均可以使用,好比在一個模塊對外提供接口時
const getName = () => person.name; const getAge = () => person.age; // commonJS的方式 module.exports = { getName, getAge } // ES6 modules的方式 export default { getName, getAge }
// es6 const person = { name, age, getName() { // 只要不使用箭頭函數,this就仍是咱們熟悉的this return this.name } } // es5 var person = { name: name, age: age, getName: function getName() { return this.name; } };
const name = 'Jane'; const age = 20 const person = { [name]: true, [age]: true }
在ant-design的源碼實現中,就大量使用了這種方式來拼接當前元素的className,例如:
let alertCls = classNames(prefixCls, { [`${prefixCls}-${type}`]: true, [`${prefixCls}-close`]: !this.state.closing, [`${prefixCls}-with-description`]: !!description, [`${prefixCls}-no-icon`]: !showIcon, [`${prefixCls}-banner`]: !!banner, }, className);
ant-design是一個承認度很是高的UI組件庫,官方使用react的方式進行了實現,除此以外,還有vue也有對應的實現,有興趣的同窗能夠去他們的官網瞭解學習。https://ant.design/index-cn
ES6爲咱們建立對象提供了新的語法糖,這就是Class語法。若是你對ES5中面向對象的方式比較熟悉的話,Class掌握起來也是很是迅速的,由於除了寫法的不一樣,它並不會增長新的難以理解的知識點。咱們先利用一個簡單的例子來看看寫法的不一樣。
// ES5 // 構造函數 function Person(name, age) { this.name = name; this.age = age; } // 原型方法 Person.prototype.getName = function() { return this.name } // ES6 class Person { constructor(name, age) { // 構造函數 this.name = name; this.age = age; } getName() { // 原型方法 return this.name } }
babel會將ES6的寫法編譯成爲利用Object.defineProperty實現的方式,這個方法的具體用處你們能夠在《JavaScript高級編程3》中學習瞭解,包括get,set,等都有詳細的說明
除此以外,咱們還須要特別注意在實際使用中的幾種寫法方式的不一樣,在下面的例子註釋中,我說明了他們分別對應的ES5中的含義。
class Person { constructor(name, age) { // 構造函數 this.name = name; this.age = age; } getName() { // 這種寫法表示將方法添加到原型中 return this.name } static a = 20; // 等同於 Person.a = 20 c = 20; // 表示在構造函數中添加屬性 在構造函數中等同於 this.c = 20 // 箭頭函數的寫法表示在構造函數中添加方法,在構造函數中等同於this.getAge = function() {} getAge = () => this.age }
箭頭函數須要注意的仍然是this的指向問題,由於箭頭函數this指向不能被改變的特性,所以在react組件中經常利用這個特性來在不一樣的組件進行傳值會更加方便。
相比ES5,ES6的繼承就要簡單不少,咱們直接來看一個例子。
class Person { constructor(name, age) { this.name = name; this.age = age; } getName() { return this.name } } // Student類繼承Person類 class Student extends Person { constructor(name, age, gender, classes) { super(name, age); this.gender = gender; this.classes = classes; } getGender() { return this.gender; } }
咱們只須要一個extends關鍵字,就能夠實現繼承了,不用像ES5那樣去擔憂構造函數繼承和原型繼承,除此以外,咱們還須要關注一個叫作super
的方法。
在繼承的構造函數中,咱們必須如上面的例子那麼調用一次super方法,它表示構造函數的繼承,與ES5中利用call/apply繼承構造函數是同樣的功能。
// 構造函數中 // es6 super(name, age); // es5 Person.call(this);
super還能夠直接調用父級的原型方法,
super.getName
,可是我本身歷來沒這樣用過,也就不擴展說了。
繼承在react中有大量的使用場景,許多組件都利用繼承來建立。
import React, { Component } from 'react'; class App extends Component { defaultProps = {} state = {} componentWillMount() {} componentDidMount() {} btnClick = e => {} render() {} }
只要根據咱們上面所學到的知識,明確的知道哪些屬性方法是放在構造函數中,哪些屬性方法是放到了原型中,那麼咱們本身在編寫react組件的時候就要簡單和清晰不少。
其實只要咱們ES5面向對象的知識足夠紮實,ES6和react掌握起來也沒有太多的難度,全部的學習難點,並不在ES6這些不一樣的語法糖上,而在於ES5中的原理,所以我在前面分享ES5的核心知識的時候,不少讀者老爺都火燒眉毛的但願我可以更多的說一說ES6的知識。其實咱們都沒有必要那麼着急,只要前面10多篇文章的知識足夠紮實,這篇文章所涉及到的經常使用的ES6知識,最多花30分鐘也就掌握了。這些寫法上的不一樣並不會形成你們理解上的困難,只須要有一個熟悉過程就好了。因此你們的重點,仍是要回歸到基礎上來。
http://www.jianshu.com/p/fe5f173276bd
由於學習模塊須要一個學習場景,所以我決定在下一篇文章中結合create-react-app
一塊兒分享給你們。
深刻學習ES6推薦 http://es6.ruanyifeng.com/