摘要:那之前的例子來使用一下的話,你會發現瀏覽器報錯了,如圖定義的變量不允許二次修改。如圖箭頭函數沒有它自己的值,箭頭函數內的值繼承自外圍作用域。如圖這里兩邊的結構沒有一致,如果是的話,是可以正常解構的。
前言
國慶假期已過一半,來篇干貨壓壓驚。
ES6,并不是一個新鮮的東西,ES7、ES8已經趕腳了。但是,東西不在于新,而在于總結。每個學前端的人,身邊也必定有本阮老師的《ES6標準入門》或者翻譯的《深入理解ECMAScript6》。本篇主要是對ES6的一些常用知識點進行一個總結。如果你喜歡我的文章,歡迎評論,歡迎Star~。歡迎關注我的github博客
正文我們會更具之前的羅列的內容進行一個深入的分析。
變量的新定義——let和const在ES6沒有被普及時,我們會用的變量定義的方法是var。其實,var對于一個剛剛接觸js的人說,或許并不覺得怪異。但是,對于一個開發者而言,或許會在內心抨擊它。因為它就是javascript的敗筆之一,在其他語言看來的一個怪胎。那我們就來看看怪在何處呢?
可以重復定義。不知道你的代碼里面會不會出現這樣子的代碼,舉例:
var a = 10; var a = 11;
或許,你會看到這樣子的寫法覺得沒啥,那么你很厲(wei)害(xian)。其實,這樣子的壞處不言而喻。在大型的工程化開發中,你定義一個a,我定義一個a,還有千千萬萬個你和我,這時,技術總監就該著急了。所以,這是var的第一點令人討厭的地方,但是如果你會說不是有嚴格模式嘛。的確,嚴格模式做了一定的規范,但是我們不加以討論。畢竟,這時ES6的地盤(^-^)。
可隨意修改。何為可隨意修改?并不是指變量,而是指常量。舉例:
var PI = 3.1415926 PI = 4.1415926
從例子中,我們可以看到,PI是一個我們經常會使用的常量,是公認的不可變動的。但在javascript中并不是如此。那天,如果你的PI被你們公司新晉的實習生改了,可能你找錯誤都得找半天,但這可不是實習生的鍋,也許,他并不知道這里是個常量。不過,這種情況也是玩笑話(^_^)。
沒有塊級作用域。如果你連塊級作用域都不知道的話,趕緊收藏一下^_^,回頭再來看哈~,舉例:
if(true){ var i = 10; } console.log(i); //10
相信,這變量不存在塊級作用域給我們帶來過不少麻煩吧。不知道啥時候,又得在循環中套一層閉包呢。而且,在非js開發者來說,可能覺得是個特(xiao)點(hua)。
所以,let和const就來拯救var了,如何一個拯救法呢?
在同一個塊級作用域中,不允許重復定義。那之前的例子來使用一下的話,你會發現瀏覽器報錯了,如圖:
![let](https://user-gold-cdn.xitu.io/2017/10/6/2f0fb2e7243d5f6f19c2eb8ead022655)
const定義的變量不允許二次修改。還原一下之前的例子,如圖:
![const](https://user-gold-cdn.xitu.io/2017/10/6/4665266d3b082f0275c989d96bf8af51) 是不是再也不用擔心之前的實習生啦,呦!!!
let和const定義的變量會形成塊級作用域。直接上圖,看看:
![塊級作用域](https://user-gold-cdn.xitu.io/2017/10/6/a670be66e059e8656b71237da148894c)
它們定義的變量不存在變量提升,以及存在暫時性死區
這個問題,我想舉個例子可以更加方便的說明。首先,我們來看一題簡單的筆試題:
var a = 10; function hello(){ console.log(a); var a = 11; console.log(a); } hello();
我想這個答案不言而喻,是undefined和11。原因:就是第一個console時,下面定義的變量a被提升了,所以a變成了undefined,第二個的話,就比較好理解。這個例子,我想會給初學者帶來不小的麻煩,和當初的我一樣哈。
使用let和const就會不一樣,它們并不存在變量提升,如圖:
函數的變化——箭頭函數,剩余參數,參數默認值何為箭頭函數,我們先上例子:
export const addToCart = productId => (dispatch, getState) => { if (getState().products.byId[productId].inventory > 0) { dispatch(addToCartUnsafe(productId)) } }
這是,我從redux例子中摘取的一個片段,第一感覺就是『代碼風格簡潔』,整體代碼規范很好,畢竟是示例代碼么。但是會讓人難以理解。因此,為了避免以后看不懂的尷尬,還是來好好聊聊這個神奇的東西吧。
其實,這個東西類似于python的lambda。但是,它的確特別適合js這門語言,就一個字「酷」。它的幾個規則:
變量如果只有一個的時候,可以省略()
如果是只有一句返回語句時,可以直接省略{return }這一部分
因為它本身叫做arrow,所以每次都必須帶上=>符號
如果你一開始不會寫,那就必須得多練習,這樣才能在以后的工作中真正謀求便利。
當然咯,它有好處,但是在使用的時候,也得注意它的禁區。注意事項:
箭頭函數不能作為構造函數。如圖:
![arrow](https://user-gold-cdn.xitu.io/2017/10/6/80cab1e89e69343aaa393b871f947d23)
箭頭函數沒有它自己的this值,箭頭函數內的this值繼承自外圍作用域。如圖:
![arrow](https://user-gold-cdn.xitu.io/2017/10/6/2f4ee91258a2802f53abb504c75a4faf)
箭頭函數沒有arguments。這個我們直接測試一下就可以了,如圖:
![arrow](https://user-gold-cdn.xitu.io/2017/10/6/95b20121716122fc48bdbec90ac9f6c4)
啥?沒有arguments,那我如果正好要用到呢?這可咋辦呢?下面再來說個有意思的改動——剩余參數。
什么叫剩余參數?別著急,看個例子就懂了。
const restParam = function(a, ...args){ console.log(args); }; restParam(1, 2, 3, 4); //[2, 3, 4]
這里你會發現這個args變量似乎包含了之后輸入的所有參數,除了a以外。所以,這就是所謂的剩余參數。其中,運用到了一個…這個符號。其實這個符號的用處非常的多,ES6中可以將它稱為擴展符。那么,我們來看看在箭頭函數中的運用。
當然,在使用剩余參數時,需要注意一個問題,就是剩余參數設置的位置。我們先來看張圖:
所以,在使用剩余參數時,需要注意的是,將這部分放在所有參數的最后位置。其實,ES6還帶來了另一個參數的變動——默認參數。或許,我們可以先看一下默認參數這個問題,我們之前是怎么處理的。場景:一般在設置延遲的時候,都會有一個時間的默認值,防止用戶在沒有設置的情況下使用,看看下面的例子:
function defaultParam(time){ let wait = time || 1000; setTimeout(() => { //... }, wait); }
這種寫法應該非常的常見,使用的也比較廣泛。但是,使用ES6的語法的話,就會變成這樣子,例子:
function defaultParam(time = 1000){ setTimeout(() => { //... }, time); }
看上去這樣子的寫法,會使得函數更加的簡潔明了。
數組——解構賦值、二進制數組說到解構賦值呢?大家千萬別誤解為這是數組的特性。不是的,對象也能夠滿足。只是覺得放在這邊來寫會比較好而已
解構賦值這個新特性,說實話是真的好用。我們可以先來看一個復雜一點的例子:
let [a, b , {name, age}, ...args ] = [1, 2, {name: "zimo", age: 24}, 3, 4]; console.log(a, b, name, age, args); //1, 2, "zimo", 24, [3, 4]
你會發現例子中,有一個特點——對仗工整。
這是解構賦值時,必須要去滿足的條件——想要解構的部分,內容保持一致。這樣才能保證完美解構。對于解構而言,左右兩邊的內容長度不一致,不會出問題。比如,當你右邊內容多一點的時候,其實沒啥事,你只需要保證你左邊的結構有一部分是你想要的,舉例:
let [a, b, c] = [1, 2, 3, 4, 5]; console.log(a, b, c); //1, 2, 3
這種叫做部分解構,左邊也是一樣的,對于多處來的部分,會變成undefined。舉例:
let [a,b,c] = [1, 2]; console.log(a, b, c); //1 2 undefined
解構賦值在使用過程中,也是有需要注意的部分:
必須保證有賦值的過程。看個例子:
![解構賦值](https://user-gold-cdn.xitu.io/2017/10/6/dd437a39aa760a86119524bfa7de36a2) 你可以看到圖中的例子,多帶帶先聲明了a和b,但是沒有賦值的過程,會報錯。
左邊內容部分的結構必須與右邊保持一致。如圖:
這里兩邊的結構沒有一致,如果是foo,bar的話,是可以正常解構的。但是這個例子的意圖可能是想去解構foo中的值,但是寫法上有一定的問題。
其實,解構也有沒多種玩法:
默認值的使用。由于之前說過的部分解構的情況出現,所以我們在解構時,可以使用默認值的形式。
let [a, b = 10] = [1]; console.log(a, b); //1, 10
在這個例子中b原先是undefined,但是設置了默認值的情況下,undefined的變量會被賦上默認值
函數變量中使用解構。對于一個函數而言,它的參數也可能會是數組或對象,這是我們就可以使用解構賦值的方式
function destructuring({name, age}){ console.log(name, age); } destructuring({name: "zimo", age: 21}); // zimo 21
解構賦值現在被使用的頻率也是非常之大,好好掌握一下也是有必要的。
之后的話,我們可以聊一下二進制數組的概念。
何為二進制數組?其實,我們可以先來了解一下javascript的數組。熟悉js的人都知道,其實js的數組的性能并不高,它的本質是一個對象。之所以現在你看到數組在使用時速度還可以,是因為js的引擎在處理時,做了不同的優化。拿v8引擎舉例的話,對于內部元素類型相同的數組在編譯運行的時候,會使用c編譯器。如果對于內部元素類型不同的時候,它會先將數組分離開來,然后再進行編譯。具體可以查看深入 JavaScript 數組:進化與性能
所以,我們可以直接了解一下二進制數組的使用。二進制數組可以由Int8Array、Int16Array、Int32Array等形式組成,在整數方面,可用性較強。
const buffer = new Buffer(100000000); const arr = new Int8Array(buffer); console.time("test time"); for(let i = 0; i < arr.length; i++){ arr[i] = i; } console.timeEnd("test time");
其實,現在二進制數組使用的頻率并不多,ES6也僅僅是提出,后續還會對數組這一塊進行一個更加詳細的完善。
字符串——模版字符串、startsWith、endsWidth在ES6中,對字符串也做了一定的改進。先來聊聊我們的新朋友——模版字符串。其實,在語言中,字符串有多種表示方式:單引號、雙引號和倒引號。在javascript中,雙引號和單引號都是一樣的,這點與一些靜態語言不一樣。但是,往往有時候,對于字符串的拼接會使得開發者厭煩。如何解決呢?
ES6帶來了解決方案——模版字符串。何為模版字符串呢?由倒引號包裹``,然后使用${}來包裹變量。我們可以來實踐一下
const name="zimo"; const str = `My name is ${name}`; console.log(str); //My name is zimo
這樣,我們就可以非常方便的在其中添加變量了。或許,你會覺得這樣的拼接,使用普通的方式也可以非常好的完成。但是,在開發過程中,我們或許會碰到更佳復雜的情況,比如說,我們現在要去創建一個DOM元素,以及它的內部元素。這種情況,通常還會帶有表達式。
const width = 100; const height = 200; const src = "http://www.example.com/example.png"; const html = ``;
往往這樣子的元素在手動拼接的過程中,總是會出錯,因此,使用模版字符串是一種既「高效」又「簡潔」的方式。
有了模版字符串,你可以解決非常棘手的問題。那么,標題中帶有的startsWith和endsWith又是起到什么作用呢?可能你會使用正則表達式,那么你就有可能不會使用到這兩個API。
按照慣例,還是需要來介紹一下這兩個API的。
startsWith:返回值為boolean型,然后去匹配字符串開頭的部分,舉個例子:
const str = "start in the head"; console.log(str.startsWith("start")); //true console.log(str.startsWith("head")); //false
其實,這也是可以使用正則表達式來達到這一目的。還原上例:
const str = "start in the head"; console.log(/^start/.test(str)); //true console.log(/^head/.test(str)); //false
其實,兩者方式的區別基本上沒有,但是正則表達式的功能更佳的完善。這個API僅僅在一些場景下起到一定的便捷。比方說,我們需要去匹配一個URL的協議頭是什么時,我們往往需要用到這種方式。例子:
const url = "http://www.example.com"; if(url.startsWith("http")){ console.log("this is http"); }else if(url.startsWith("https")){ console.log("this is https"); }else if(url.startsWith("ws")){ console.log("this is websocket"); } //this is http
同理,endWith也是一樣的效果。
endsWith:返回值是boolean類型,然后去匹配字符串的結尾。舉個例子:
const str = "something in the end"; console.log(str.endsWith("end")); //true console.log(str.endsWith("something")); //false
同樣的,它也可以使用正則表達式來實現:
const str = "something in the end"; console.log(/end$/.test(str)); //true console.log(/something$/.test(str)); //false
這種情況的使用場景是,往往我們需要為上傳的文件準備圖標,那么我們就可以根據后綴來確定圖標。
const filename = "upload.jpg"; if(filename.endsWith(".jpg")){ console.log("this is jpg file"); }else if(filename.endsWith(".png")){ console.log("this is png file"); }else if(filename.endsWith(".webp")){ console.log("this is webp file"); } //this is jpg file
同時,字符串還增加了許許多多的東西,有興趣的,可以自己去翻書本詳細的了解
Iterator和for...ofIterator的概念是迭代器。在ES6中,終于正式的添加了這個屬性。迭代器,主要是一個集合類元素的遍歷機制。何為集合類元素?最常見的就是數組,還有對象。迭代器可以幫助開發者完成遍歷集合的過程。最開始javascript并沒有設置接口,來自定義迭代器,但是從ES6開始,我們可以自定義迭代器了。在自定義迭代器之前,我們要清楚迭代器的作用有哪些:
為各種數據結構提供一個統一的、簡便的訪問接口
使得數據結構的成員能夠按某種次序排列
在ES6中,迭代器主要供我們之后要講述的for...of服務
迭代器,往往就是一個指針對象,不斷調用,然后不斷地指向下一個對象的過程,直到結束。ES6中,我們可以創建一個指針對象,然后調用next的函數,使得指針對象向下移動。同時,next函數會返回value和done,確定是否到達末尾。
同時,ES6還提供了Iterator接口——Symbol.iterator。首先,我們來看一下具備原生接口的集合類——數組,類數組對象、Set和Map。這樣我們就可以直接調用它的接口來進行循環:
let arr = ["my", "name", "is", "iterator"]; let iter = arr[Symbol.iterator](); console.log(iter.next()); //{ value: "my", done: false} console.log(iter.next()); //{ value: "name", done: false} console.log(iter.next()); //{ value: "is", done: false}
同時,定義iterator接口的數據結構可以輕松的使用for...of進行值的遍歷
let arr = ["I", "has", "iterator"]; for(let item of arr){ console.log(item); } //"I", "has", "iterator"
但是,如果沒有定義iterator接口的數據結構就沒有辦法使用這種方式進行遍歷,如圖:
這時,我們又該如何呢?其實,針對一些可迭代的數據結構,我們是可以自定義迭代器的,例如:
let iteratorObj = { 0: "a", 1: "b", 2: "c", length: 3, [Symbol.iterator]: Array.prototype[Symbol.iterator] } for(let item of iteratorObj){ console.log(item); } // "a", "b", "c"
迭代器是一個非常實用的東西,不妨你也可以試試,同時去改善你的代碼。
Generator和Promise其實,這兩個是比較難以理解的東西。如果只是粗淺的了解一下,還是有許多的新東西的。在ES6中,引入了generator和promise兩個概念。可能在這之前,你已經使用過了,通過其他的類庫實現的。那么,其實ES6中的新概念也是差不多的,只是標準化了而已。
generator,叫做生成器。可以說與iterator有點相似,同樣是通過next函數,來一步步往下執行的。同時,它的定義時,所使用的是function*的標識符。還具備yield這個操作符,可以實現逐步逐步向下執行。我們來看個例子:
function* generator(){ yield 1; yield 2; yield 3; }; let generate = generator(); console.log(generate.next()); //{value: 1, done: false} console.log(generate.next()); //{value: 2, done: false} console.log(generate.next()); //{value: 3, done: true} console.log(generate.next()); //{value: undefined, done: true}
這樣子看起來,似乎就是迭代器的步驟。其實,iterator的接口,可以定義成這樣子的形式。但是,generator的作用不僅僅如此。它就像一個狀態機,可以在上一個狀態到下一個狀態之間進行切換。而一旦遇到yield部分,則可以表示當前是可以步驟的暫停。需要等到調用next方法才能進行下一步驟。同時,我們還可以使用上一步的結果值,進行下一步的運算。示例:
function* generator(){ yield 1; let value = yield 2; yield 3 + value; }; let generate = generator(); let value1 = generate.next(); let value2 = generate.next(); let value3 = generate.next(value2.value); console.log(value1); //{value: 1, done: false} console.log(value2); //{value: 2, done: false} console.log(value3); //{value: 5, done: true}
這樣的話,就可以將value作為你第三步的參數值,進行使用。
之前說過,generator的next是需要自己調用的。但是,我們如何使它自己自動調用呢。我們可以使用for...of來自動調用next,就像迭代器一樣。示例:
function* generator(){ yield 1; yield 2; yield 3; }; for(let value of generator()){ console.log(value); } //1, 2, 3
其實,之前所講的只是generator的基本使用。generator主要被使用在異步編程領域。因為我們之前所講的特性,非常適合在異步編程中使用。當然了,我們也需要去提一下promise這個異步編程的功臣。
Promise,翻譯過來叫做承諾。我們可以理解為一種約定。大家都知道異步編程的時候,我們一般會使用到回調函數這個東西。但是,回調函數會導致的問題,也非常的明顯。示例:
callback1(function(data){ //... callback2(function(data1){ const prevData = data; //... callback3(function(){ //... callback4(function(){ //... }); }); }); });
回調函數,寫多了之后我們會發現,這個倒金字塔會越來越深,而我們會越來越難以管理。
這時,或許promise會起到一定的作用。試想一下,為什么這幾個回調函數都能在另一個回調函數之外進行?主要原因:
每個回調函數,都會無法確定另一個回調函數會在何時會被調用,因為這個控制權不在當前這個程序之中。
每個回調函數,都或多或少的依賴于上一個回調函數執行的時間和數據
基于這兩點,我們就會發現,一旦你需要這樣去編寫代碼,就必須保證你的上一個回調函數在下一個回調函數之前進行。我們還可以發現,它們之間缺乏一種約定,就是一旦上一個發生了,無論是正確還是錯誤,都會通知對應的回調函數的約定。
Promise,或許就是起到了這樣的一種作用。它具備三種狀態:pending、resolved、rejected。它們之間分別對應:正在進行、已解決、已拒絕等三種結果。一個回調函數會開始從pending狀態,它會向resolved和rejected的兩者之一進行轉換。而且這種轉換是不可變的,即一旦你從pending狀態轉變到resolved狀態,就不可以再變到rejected狀態去了。
然后,promise會有一個then函數,可以向下傳遞之前回調函數返回的結果值。我們可以寫個promise示例:
new Promise((resolved, rejected) => { resolved(1); }).then(data => { console.log(data); }, err => { console.log(err); }).catch(err => { console.log(err); }); // 1
其實,只需要記住這樣子的一種形式,就可以寫好promise。Promise是一個比較容易書寫的東西。因為它的形式比較單一,而且現在有許多封裝的比較好的異步請求庫,都帶有Promise的屬性,例如axios。
Promise,還帶有其他的一些API,上面我們也使用到了一個。
catch:用于指定發生錯誤時的回調函數。主要是我們之前說過Promise有個不可變的特性,所以,一旦這一個過程中發生錯誤,但是狀態無法轉變,只能在下一個流程中去捕獲這個錯誤。因此,為了預防最后一個流程發生錯誤,需要在最后使用catch去捕獲最后一個流程中的錯誤。
all:用于將多個Promise實例包裝成一個新的Promise實例。
這個函數需要其中所有的Promise實例都變成Fulfilled時,才會將結果包裝成一個數組傳遞給下一個Promise。
如果其中有一個Promise實例變成Rejected時,就會將第一個Rejected的結果傳遞給下一個Promise
race:也是用于將多個Promise實例包裝成一個新的Promise實例。但是這個函數有所不同
如果這個函數中,有一個Promise變成Fulfilled時,它就會將結果傳遞給下一個Promise
resolve:它會將一個當前對象轉化為Promise對象
reject:返回一個出錯的Promise對象
Promise可以和之前所講的Generator一起使用,我們可以看一下使用場景:
通過Generator函數來管理流程,遇到異步操作,就使用Promise進行處理。
function usePromise(){ return new Promise(resolve => { resolve("my name is promise"); }); } function* generator(){ try{ let item = yield usePromise(); console.log(item); }catch(err){ console.log(err); } } let generate = generator(); generate.next().value.then(data => { console.log(data); }, err => { console.log(err); }).catch(err => { console.log(err); }); //my name is promise
或許,你還可以寫出更加復雜的程序。
Class和extends最后要聊的一個主題就是class。相信抱怨javascript沒有類的特性數不勝數。同時,還需要去了解js的類繼承式概念。那么,ES6也帶來了我們最歡迎的class module部分。我們就不介紹之前我們是如果去構建對象的了(好像是構造函數)。
那么,我們可以來看一下,ES6給我帶來的新變化:
class Animal{ constructor(name){ this.name = name; } sayName(){ return this.name; } } const animal = new Animal("dog"); console.log(animal.sayName()); // "dog"
似乎這樣子的形式比之前的構造函數的方式強對了。我們可以理解一下這個結構:
其內部的constructor:指向的就是整個類的constructor
其內部的函數:這些函數的定義在類的原型上面
因此,上面那個其實可以寫成原先的:
function Animal(name){ this.name = name; } Animal.prototype.sayName = function(){ return this.name; }
其實,就是class在ES6中得到了封裝,可以使得現在的方式更加的優美。
之后,我們簡單了解一下繼承這個概念吧。
任何的東西,都是需要繼承的。因為我們不可能都是從頭去寫這個類。往往是在原有類的基礎之上,對它進行完善。在ES6之前,我們可能對構造函數完成的是組合式繼承。示例:
function Animal(name){ this.name = name; } Animal.prototype.sayName = function(){ return this.name; } function Dog(name, barking){ Animal.call(this, name); this.barking = barking; } Dog.prototype = new Animal(); Dog.prototype.constructor = Dog; Dog.prototype.makeBarking = function(){ return this.barking; } const dog = new Dog("zimo", "汪汪汪"); console.log(dog.makeBarking()); //汪汪汪 console.log(dog.sayName()); //zimo
這樣子的組合式繼承書寫起來,比較麻煩,需要重新去對每個元素設置,然后還要重新定義新類的原型。那么,我們可以來看一下ES6對于繼承的封裝:
class Animal{ constructor(name){ this.name = name; } sayName(){ return this.name; } } class Dog extends Animal{ constructor(name, barking){ super(name); this.barking = barking; } makeBarking(){ return this.barking; } }
這樣子,就可以輕松的完成之前的組合式繼承步驟了。如果你對extends的封裝感興趣的話,不妨看一下這篇文章javascript之模擬類繼承
總結在這里ES6的內容只是總結了部分,大致可以分為這么幾個部分:
變量定義——let和const
函數的變化——箭頭函數、剩余參數
數組的變動——解構,展開符
字符串——模版字符串、startsWith、endsWith
Iterator和for...of
Generator和Promise
Class和extends
希望,你可以從這些內容中對ES6多一些了解,同時,如果你還想深入ES6進行了解的話,最直接的方式就是看書。希望你的代碼寫的越來越優雅。
如果你對我寫的有疑問,可以評論,如我寫的有錯誤,歡迎指正。你喜歡我的博客,請給我關注Star~呦。大家一起總結一起進步。歡迎關注我的github博客
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/88868.html
摘要:前言這里筑夢師是一名正在努力學習的開發工程師目前致力于全棧方向的學習希望可以和大家一起交流技術共同進步用簡書記錄下自己的學習歷程個人學習方法分享本文目錄更新說明目錄學習方法學習態度全棧開發學習路線很長知識拓展很長在這里收取很多人的建議以后決 前言 這里筑夢師,是一名正在努力學習的iOS開發工程師,目前致力于全棧方向的學習,希望可以和大家一起交流技術,共同進步,用簡書記錄下自己的學習歷程...
摘要:的翻譯文檔由的維護很多人說,阮老師已經有一本關于的書了入門,覺得看看這本書就足夠了。前端的異步解決方案之和異步編程模式在前端開發過程中,顯得越來越重要。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。 JavaScript Promise 迷你書(中文版) 超詳細介紹promise的gitbook,看完再不會promise...... 本書的目的是以目前還在制定中的ECMASc...
閱讀 2439·2021-10-09 09:44
閱讀 3809·2021-09-22 15:43
閱讀 2927·2021-09-02 09:47
閱讀 2553·2021-08-12 13:29
閱讀 3875·2019-08-30 15:43
閱讀 1684·2019-08-30 13:06
閱讀 2193·2019-08-29 16:07
閱讀 2753·2019-08-29 15:23