與var不一樣,新的變量聲明方式帶來了一些不同的特性,其中最重要的兩個特性就是提供了塊級做用域與再也不具有變量提高。javascript
如果對變量提高不怎麼了解的話能夠去參考個人其餘文章 javascript預編譯的過程 。html
什麼是塊級做用域膩?java
寫在 「{}」 內的內容 都是塊級做用域。node
在es6以前,咱們想保護一個變量怎麼辦,將其放在一個當即執行函數裏面,寫在局部做用域中。react
這樣寫是否是挺麻煩的捏,多謝幾個單詞不花時間麼?!es6
在ES6中,咱們想保護一個變量 只要 寫在花括號中就行了。面試
{chrome
let a=10;數組
}promise
下面有兩個例子:
{ let a = 20; } console.log(a); // a is not defined //寫在塊級做用域中的內容會被保護起來,因此會打印 a is not defined
而這個簡單的例子,會被編譯爲:
{ let _a = 20; } console.log(a); // a is not defined // ES5 console.log(a); // undefined var a = 20; // 在es5中var一個變量 會變量提高 // 如同 // var a; // console.log(a); //從上向下順序執行 固然會打印 undefined 的捏。 // a=20 // ES6 console.log(a); // a is not defined let a = 20; //變量不會提高 打印時固然是 a is not defined
固然,你的代碼編譯成爲了ES5以後,仍然會存在變量提高,所以這一點只須要咱們記住便可。
在實際使用中,也須要儘可能避免使用變量提高的特性帶來的負面影響。只有在面試題中,纔會對變量提高不停的濫用。使用ES6,咱們須要全面使用let/const替換var,那麼何時用let,何時用const就成爲了一個你們要熟練區分的一個知識點。
咱們經常使用let來聲明一個值會被改變的變量,而使用const來聲明一個值不會被改變的變量,也能夠稱之爲常量。當值爲基礎數據類型時,那麼這裏的值,就是指值自己。而當值對應的爲引用數據類型時,那麼我這裏說的值,則表示指向該對象的引用。
這裏須要注意,正由於該值爲一個引用,只須要保證引用不變就能夠,咱們仍然能夠改變該引用所指向的對象。當咱們試圖改變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中添加了能夠簡化這種任務的新特性:解構。解構是一種打破數據結構,將其拆分爲更小部分的過程。
在ES5中,開發者們爲了從對象和數組中獲取特定數據並賦值給變量,編寫了許多看起來同質化的代碼
let options = { repeat: true, save: false }; // 從對象中提取數據 let repeat = options.repeat, save = options.save;
這段代碼從options對象中提取repeat和save的值,並將其存儲爲同名局部變量,提取的過程極爲類似
若是要提取更多變量,則必須依次編寫相似的代碼來爲變量賦值,若是其中還包含嵌套結構,只靠遍歷是找不到真實信息的,必需要深刻挖掘整個數據結構才能找到所需數據
因此ES6添加了解構功能,將數據結構打散的過程變得更加簡單,能夠從打散後更小的部分中獲取所需信息
對象字面量的語法形式是在一個賦值操做符左邊放置一個對象字面量。
let node = { type: "Identifier", name: "foo" }; let { type, name } = node; console.log(type); // "Identifier" console.log(name); // "foo"
let node = { type: "Identifier", name: "foo" }, type = "Literal", name = 5; // 使用解構來分配不一樣的值 ({ type, name } = node); console.log(type); // "Identifier" console.log(name); // "foo"
在這個示例中,聲明變量type和name時初始化了一個值,在後面幾行中,經過解構賦值的方法,從node對象讀取相應的值從新爲這兩個變量賦值
[注意]必定要用一對小括號包裹解構賦值語句,JS引擎將一對開放的花括號視爲一個代碼塊。語法規定,代碼塊語句不容許出如今賦值語句左側,添加小括號後能夠將塊語句轉化爲一個表達式,從而實現整個解構賦值過程。
與對象解構的語法相比,數組解構就簡單多了,它使用的是數組字面量,且解構操做所有在數組內完成,而不是像對象字面量語法同樣使用對象的命名屬性
let colors = [ "red", "green", "blue" ]; let [ firstColor, secondColor ] = colors; console.log(firstColor); // "red" console.log(secondColor); // "green"
在這段代碼中,咱們從colors數組中解構出了"red"和"green"這兩個值,並分別存儲在變量firstColor和變量secondColor中。在數組解構語法中,咱們經過值在數組中的位置進行選取,且能夠將其存儲在任意變量中,未顯式聲明的元素都會直接被忽略
在解構模式中,也能夠直接省略元素,只爲感興趣的元素提供變量名
let colors = [ "red", "green", "blue" ]; let [ , , thirdColor ] = colors; console.log(thirdColor); // "blue"
這段代碼使用解構賦值語法從colors中獲取第3個元素,thirdColor前的逗號是前方元素的佔位符,不管數組中的元素有多少個,均可以經過這種方法提取想要的元素,不須要爲每個元素都指定變量名
能夠混合使用對象解構和數組解構來建立更多複雜的表達式,如此一來,能夠從任何混雜着對象和數組的數據解構中提取想要的信息
let node = { type: "Identifier", name: "foo", loc: { start: { line: 1, column: 1 }, end: { line: 1, column: 4 } }, range: [0, 3] }; let { loc: { start }, range: [ startIndex ] } = node; console.log(start.line); // 1 console.log(start.column); // 1 console.log(startIndex); // 0
這段代碼分別將node.loc.start和node.range[0]提取到變量start和startlndex中
解構模式中的loc和range僅表明它們在node對象中所處的位置(也就是該對象的屬性)。當使用混合解構的語法時,則能夠從node提取任意想要的信息。這種方法極爲有效,尤爲是從JSON配置中提取信息時,再也不須要遍歷整個結構了
以前我說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組件時再慢慢來感覺。
還有就是 原函數中 arguments (實參) 在箭頭函數中是是用不了的。
他就是一個對象,主要是用來處理異步數據的。
在promise中,有三種狀態:
pending(等待,處理中) --> 1.resolve(完成) 2.rejected(失敗,拒絕)。
又,這三種狀態的變化只有兩種模式,而且一旦狀態改變,就不會再變:
一、異步操做從pending到resolved;
二、異步操做從pending到rejected;
好了,既然它是屬於ES6規範,咱們再經過chrome,直接打印出Promise,看看這玩意:
恩,一目瞭然,Promise爲構造函數,歐克,這樣經過它,咱們就能夠實例化本身的Promise對象了,並加以利用。
能夠接收構造函數中處理的狀態變化,並分別對應執行。then方法有2個參數,第一個函數接收resolved狀態的執行,第二個參數接收reject狀態的執行。
function fn(num) { return new Promise(function(resolve, reject) { if (typeof num == 'number') { resolve(); } else { reject(); } }).then(function() { console.log('參數是一個number值'); }, function() { console.log('參數不是一個number值'); }) } fn('hahha'); fn(1234);
then方法的執行結果也會返回一個Promise對象。所以咱們能夠進行then的鏈式執行,這也是解決回調地獄的主要方式。
function fn(num) { return new Promise(function(resolve, reject) { if (typeof num == 'number') { resolve(); } else { reject(); } }) .then(function() { console.log('參數是一個number值'); }) .then(null, function() { console.log('參數不是一個number值'); }) } fn('hahha'); fn(1234);
then(null, function() {}) 就等同於catch(function() {})
getNumber() .then(function(data){ console.log('resolved'); console.log(data); }) .catch(function(reason){ console.log('rejected'); console.log(reason); });
效果和寫在then的第二個參數裏面同樣。不過它還有另一個做用:在執行resolve的回調(也就是上面then中的第一個參數)時,若是拋出異常了(代碼出錯了),那麼並不會報錯卡死js,而是會進到這個catch方法中。請看下面的代碼:
getNumber() .then(function(data){ console.log('resolved'); console.log(data); console.log(somedata); //此處的somedata未定義 }) .catch(function(reason){ console.log('rejected'); console.log(reason); });
Promise .all([runAsync1(), runAsync2(), runAsync3()]) .then(function(results){ console.log(results); });
Promise .race([runAsync1(), runAsync2(), runAsync3()]) .then(function(results){ console.log(results); });