ES6經常使用知識點概述

前言

國慶假期已過一半,來篇乾貨壓壓驚。javascript

ES6,並非一個新鮮的東西,ES七、ES8已經趕腳了。可是,東西不在於新,而在於總結。每一個學前端的人,身邊也一定有本阮老師的《ES6標準入門》或者翻譯的《深刻理解ECMAScript6》。本篇主要是對ES6的一些經常使用知識點進行一個總結。若是你喜歡個人文章,歡迎評論,歡迎Star~。歡迎關注個人github博客html

正文

咱們會更具以前的羅列的內容進行一個深刻的分析。前端

變量的新定義——let和const

在ES6沒有被普及時,咱們會用的變量定義的方法是var。其實,var對於一個剛剛接觸js的人說,或許並不以爲怪異。可是,對於一個開發者而言,或許會在心裏抨擊它。由於它就是javascript的敗筆之一,在其餘語言看來的一個怪胎。那咱們就來看看怪在何處呢?java

  1. 能夠重複定義。不知道你的代碼裏面會不會出現這樣子的代碼,舉例:python

    var a = 10;
     var a = 11;複製代碼

    或許,你會看到這樣子的寫法以爲沒啥,那麼你很厲(wei)害(xian)。其實,這樣子的壞處不言而喻。在大型的工程化開發中,你定義一個a,我定義一個a,還有千千萬萬個你和我,這時,技術總監就該着急了。因此,這是var的第一點使人討厭的地方,可是若是你會說不是有嚴格模式嘛。的確,嚴格模式作了必定的規範,可是咱們不加以討論。畢竟,這時ES6的地盤(^-^)。ios

  2. 可隨意修改。何爲可隨意修改?並非指變量,而是指常量。舉例:git

    var PI = 3.1415926
     PI = 4.1415926複製代碼

    從例子中,咱們能夠看到,PI是一個咱們常常會使用的常量,是公認的不可變更的。但在javascript中並非如此。那天,若是你的PI被大家公司新晉的實習生改了,可能你找錯誤都得找半天,但這可不是實習生的鍋,也許,他並不知道這裏是個常量。不過,這種狀況也是玩笑話(^_^)。github

  3. 沒有塊級做用域。若是你連塊級做用域都不知道的話,趕忙收藏一下^_^,回頭再來看哈~,舉例:web

    if(true){
         var i = 10;
     }
     console.log(i);  //10複製代碼

    相信,這變量不存在塊級做用域給咱們帶來過很多麻煩吧。不知道啥時候,又得在循環中套一層閉包呢。並且,在非js開發者來講,可能以爲是個特(xiao)點(hua)。正則表達式

因此,let和const就來拯救var了,如何一個拯救法呢?

  1. 在同一個塊級做用域中,不容許重複定義。那以前的例子來使用一下的話,你會發現瀏覽器報錯了,如圖:

    let
    let

  2. const定義的變量不容許二次修改。還原一下以前的例子,如圖:

    const
    const

    是否是不再用擔憂以前的實習生啦,呦!!!

  3. let和const定義的變量會造成塊級做用域:直接上圖,看看:

    塊級做用域
    塊級做用域

  4. 它們定義的變量不存在變量提高,以及存在暫時性死區

    這個問題,我想舉個例子能夠更加方便的說明。首先,咱們來看一題簡單的筆試題:

    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,因此每次都必須帶上=>符號

若是你一開始不會寫,那就必須得多練習,這樣才能在之後的工做中真正謀求便利。

固然咯,它有好處,可是在使用的時候,也得注意它的禁區。注意事項:

  1. 箭頭函數不能做爲構造函數。如圖:

    arrow
    arrow

  2. 箭頭函數沒有它本身的this值,箭頭函數內的this值繼承自外圍做用域。如圖:

    arrow
    arrow

  3. 箭頭函數沒有arguments。這個咱們直接測試一下就能夠了,如圖:

    arrow
    arrow

啥?沒有arguments,那我若是正好要用到呢?這可咋辦呢?下面再來講個有意思的改動——剩餘參數

什麼叫剩餘參數?彆着急,看個例子就懂了。

const restParam = function(a, ...args){
    console.log(args);
};
restParam(1, 2, 3, 4);   //[2, 3, 4]複製代碼

這裏你會發現這個args變量彷佛包含了以後輸入的全部參數,除了a之外。因此,這就是所謂的剩餘參數。其中,運用到了一個這個符號。其實這個符號的用處很是的多,ES6中能夠將它稱爲擴展符。那麼,咱們來看看在箭頭函數中的運用。

rest param
rest param

固然,在使用剩餘參數時,須要注意一個問題,就是剩餘參數設置的位置。咱們先來看張圖:

參數位置
參數位置

因此,在使用剩餘參數時,須要注意的是,將這部分放在全部參數的最後位置。其實,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複製代碼

解構賦值在使用過程當中,也是有須要注意的部分:

  1. 必須保證有賦值的過程。看個例子:

    解構賦值
    解構賦值

    你能夠看到圖中的例子,單獨先聲明瞭a和b,可是沒有賦值的過程,會報錯。

  2. 左邊內容部分的結構必須與右邊保持一致。如圖:

    解構賦值
    解構賦值

    這裏兩邊的結構沒有一致,若是是foo,bar的話,是能夠正常解構的。可是這個例子的意圖多是想去解構foo中的值,可是寫法上有必定的問題。

其實,解構也有沒多種玩法:

  1. 默認值的使用。因爲以前說過的部分解構的狀況出現,因此咱們在解構時,可使用默認值的形式。

    let [a, b = 10] = [1];
     console.log(a, b);  //1, 10複製代碼

    在這個例子中b原先是undefined,可是設置了默認值的狀況下,undefined的變量會被賦上默認值

  2. 函數變量中使用解構。對於一個函數而言,它的參數也可能會是數組或對象,這是咱們就可使用解構賦值的方式

    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 = `<div class="block" width="${0.5 * width}px" height="${height}"><img src="${src}" /></div>`;複製代碼

每每這樣子的元素在手動拼接的過程當中,老是會出錯,所以,使用模版字符串是一種既「高效」又「簡潔」的方式。

有了模版字符串,你能夠解決很是棘手的問題。那麼,標題中帶有的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...of

Iterator的概念是迭代器。在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接口的數據結構就沒有辦法使用這種方式進行遍歷,如圖:

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會起到必定的做用。試想一下,爲何這幾個回調函數都能在另外一個回調函數以外進行?主要緣由:

  1. 每一個回調函數,都會沒法肯定另外一個回調函數會在什麼時候會被調用,由於這個控制權不在當前這個程序之中。
  2. 每一個回調函數,都或多或少的依賴於上一個回調函數執行的時間和數據

基於這兩點,咱們就會發現,一旦你須要這樣去編寫代碼,就必須保證你的上一個回調函數在下一個回調函數以前進行。咱們還能夠發現,它們之間缺少一種約定,就是一旦上一個發生了,不管是正確仍是錯誤,都會通知對應的回調函數的約定。

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博客

相關文章
相關標籤/搜索