ES6是個啥
ECMAScript是國際通過的標準化腳本語言
JavaScript由ES,BOM,DOM組成
ES是JavaScript的語言規範,同時JavaScript是ES的實現和擴展
6就是JavaScript語言的下一代標準
關於ES6的一些知識
1.let、const
ES5中的作用域有:函數作用域,全局作用域
ES6新增了塊級作用域。由{}包括(if和for語句也屬於塊級作用域)
{
var a = 1;
let b = 2;
}
console.log(a)//1
console.log(b)//undefined
let、const、var的區別
var:可以跨塊級作用域訪問,不能跨函數作用域訪問
let:只能在塊級作用域訪問,不能跨函數使用
const:定義常量,必須初始化且不能修改,只能在塊級作用域內使用
關於變量提升:var不論聲明在何處都會莫默認提升到函數/全局最頂部,但是let和const不會進行變量提升
2.arrow function 箭頭函數
箭頭函數相當於匿名函數,簡化了函數的定義
定義就用=> 一個箭頭
箭頭函數有兩種格式:
第一種:只包含一個表達式
x=>x++
相當於
function(x)}{
return x++;
}
第二種:包含多條語句:
//包含判斷等
x=>{
if(x>0){
return x++;
}
else{
x--;
}
}
//多個參數
(x,y,z....)=>x+y+z+...+
//無參數
()=>1
//返回對象
x=>({obj:x})//注意符號,避免和函數體的{}衝突
使用箭頭函數時,函數體內的this對象,就是定義時所在的對象
3.Promise
定義:Promise對象用於異步操作,它表示一個尚未完成且預計在未來完成的異步操作
關於同步&異步
JavaScript是基於事件驅動的單線程運行機制
(why: 瀏覽器中至少有三個線程:js引擎線程,gui渲染線程,瀏覽器事件觸發線程
js操作dom,瀏覽器事件觸發都會影響gui渲染效果,因此他們之間存在互斥的關係,使用多線程會帶來非常複雜的同步問題(a線程在某個DOM節點添加內容。b線程刪除了該節點)
同步:
即單線程模式,所有的任務都在主線程上執行,形成一個執行棧*,如函數調用後需要等待函數執行結束後才能進行下一個任務,如果某個任務執行時間過長(如死循環),容易造成線程阻塞,影響下面任務的正常進行
異步:
可以一起執行多個任務,函數調用後不會立刻就返回執行結果,異步任務會在當前腳本所有的同步任務執行結束後再執行。異步任務不進入主線程,而是進入任務隊列,在某個任務可以執行時,等待主線程讀取任務隊列,隨後該任務將進入主線程執行
異步任務的實現,最經典的就是setTimeout()/setInterval()
他們的內部運行機制完全一樣,前者指定的代碼只執行一次,後者爲反覆執行
setTimeout(function(){
console.log("taskA,yibu");
},0)
console.log("taskB,tongbu");
//taskB,tongbu
//taskA,yibu
即使延時事件爲0,但由於它屬於異步任務,仍需要等待同步任務執行結束後再執行
綜合看,整體的執行順序爲:先執行執行棧中的內容,執行完畢後,讀取任務隊列,尋找對應的異步任務,結束等待狀態,進入執行棧執行,不斷循環(Event Loop)
只要主線程空了,就會去讀取任務隊列
關於回調函數,callback()
回調函數即是會被主線程掛起的代碼
異步任務必須指定回調函數,當主線程開始讀取任務隊列,執行異步任務的時候,執行的就是對應的回調函數
言歸正傳,繼續理解Promise
promise的三種狀態:
- pending:初始狀態
- fulfilled:操作成功
- rejected:操作失敗
Promise可以由1->2/1->3一旦狀態變化,便會一直保持這個狀態,不再改變。
當狀態改變Promise.then綁定的函數就會被調用
構建Promise
var promise = new Promise(function(resolve,reject){
if(/*操作成功*/)
resolve(data);
else
reject(error);
});
異步操作成功調用resolve,將結果作爲參數傳遞出去
異步操作失敗調用reject,將報出的錯誤作爲參數傳遞出去
Promise構建完成後,使用then方法指定resolve狀態和reject狀態的回調函數
promise.then(成功回調函數,失敗的回調函數(非必要))
//這兩個函數都接受promise傳出的值作爲參數
promise.then(function(data){do xxxx for success},function(error){do xxxx for failure});
Promise新建後就執行,then方法指定的回調函數會在當前腳本的所有同步任務執行結束後再執行
例子:
var promise = new Promise(function(resolve, reject) {
console.log('before resolved');
resolve();
console.log('after resolved');
});
promise.then(function() {
console.log('resolved');
});
console.log('outer');
//before resolved
//after resolved
//outer
//resolved
Promise的優勢在於,可以在then方法中繼續寫Promise對象並返回,然後繼續調用then來進行回調操作。能夠簡化層層回調的寫法。
Promise的精髓在於,用維護狀態、傳遞狀態的方式使得回調函數能夠及時調用,比傳遞callback要簡單、靈活
Promise的其他方法
.catch()
用於指定發生錯誤時的回調函數,等同於reject部分
和reject的區別:
promise.then(onFulfilled,onRejected)在onFulfilled發生異常,在onRejected中捕獲不到
promise.then(onFulfilled).catch(onRejected)能夠捕獲異常。也可以用then替換,只是寫法不同。本質上沒有區別
.all()
用於將多個Promise實例包裝成一個新的Promise實例
var p = Promise.all([p1, p2, p3]);
p1p2p3都需爲promise實例
當p1p2p3都爲fulfilled時,p纔會變爲fulfilled
只要有一個變爲rejected,p就會變成rejected
.race()
用於將多個Promise實例包裝成一個新的Promise實例
與all()的區別類似於 AND 和 OR
p1p2p3有一個狀態發生改變,p的狀態就發生改變,並返回第一個改變狀態的promsie返回值,傳遞給p
.resolve()
看作new Promise()的快捷方式
實例:
Promise.resolve('Success');
/*******等同於*******/
new Promise(function (resolve) {
resolve('Success');
});
讓對象立刻進入resolved狀態
4.generate
可以將generate理解爲一個能夠多次返回的“函數”
function* foo(x){
yield x++;
yield x+2;
yield x+3;
return x*x;
}
由function*定義,並且yield也可以返回數據
調用generate的方法:
不斷的使用next()
var f = foo(0);
console.log(f.next());// 0 false
console.log(f.next());// 1 false
console.log(f.next());// 3 false
console.log(f.next());// 4 true
使用for of結構
for (var x of foo(0)) {
console.log(x); // 依次輸出0 1 3 (沒有輸出4原因不詳)
}
每執行一次後就暫停,返回的值就是yield的返回值,每次返回一個值,直到done爲true,這個generate對象已經全部執行完畢
generate更像一個能夠記住執行狀態的函數
實際上generate不算是一個函數,它的返回值不是變量也不是函數,而是一個可迭代的對象
該對象類似一個元素被定義好的數組,保存的是一種規則而不元素本身,不能夠隨機訪問,遍歷也只能夠遍歷一次,因爲規則只保存了上次的狀態