ES6/ES7/ES8常用新增語法

本文參考了阮一峯老師的ES6教程,部分示例代碼來源於ECMAScript 6 入門


塊級作用域

ES6中針對塊級作用域進行了一些規範化的定義。

  • 使用let關鍵字來創建塊級作用域變量,該方式聲明的變量只在 let 所在的代碼塊有效。

    • 比如for循環中的i,就可以使用 let 來聲明,這樣i只在for循環體內有效。

    • for循環中,每一輪循環,i都是一個新聲明的變量,並且只在本次循環的代碼塊中生效。

    • 注意for循環中,設置循環變量的那部分是父作用域,循環體內部是一個單獨的子作用域,因此在 for 循環的代碼塊中再次用 let 聲明i會創建一個新的變量。

      for (let i = 0; i < 3; i++) {
        let i = 'abc';
        console.log(i);
      }
      // abc
      // abc
      // abc
      //輸出了 3 次abc。這表明函數內部的變量i與循環變量i不在同一個作用域,有各自單獨的作用域。
      
  • 使用 const 關鍵字來創建塊級作用域常量,常量在創建後不能被重新賦值。

  • 不存在變量提升,如果在let聲明之前使用或對該變量賦值,會報錯ReferenceError

  • 不允許在相同作用域內,重複聲明同一個變量。

    ES5規定中不允許在塊級作用域中聲明函數,但瀏覽器卻可以這樣做。而ES6中明確規定可以在塊級作用域中聲明函數,相當於let聲明,同時爲了兼容歷史規則,允許瀏覽器有自己的行爲。這樣一來,在不同瀏覽器中,塊級作用域聲明函數的規則具有較大的差異。爲了避免不必要的bug,我們在塊級作用域中,要使用函數表達式,而不是函數聲明語句。


模板字面量

模板字面量是允許嵌入表達式的字符串字面量,它是增強版的字符串,採用反引號(鍵盤上ESC下面的那個鍵)來標識。

  • 可以用模板字面量來創建多行字符串,空格和換行都會被視爲字符串的一部分。

    let msg = `
    <h2>hello<h2>
    <h2>world<h2>
    `.trim();
    
    console.log(msg);
    //輸出
    <h2>hello<h2> 
    <h2>world<h2>
    
  • 在模板字面量中使用變量佔位符${變量}

    let name = "Tom", message = `Hello, ${name}.`;
    console.log(message); // "Hello, Tom."
    
    //佔位符可以是運算符或者函數調用等構成表達式
    function fn() {
      return "Hello World";
    }
    `foo ${fn()} bar` // foo Hello World bar
    
    let count = 10, price = 0.25,
    message = `${count} items cost $${(count * price).toFixed(2)}.`;
    console.log(message); // "10 items cost $2.50."
    

函數的擴展

函數的默認參數:

允許在調用時沒有值或undefined被傳入時使用指定的默認參數值。

function fun(name='world'){
  return 'hello ' + b;
}
fun(); //"hello world"

函數的rest參數:

延展運算符和一個變量名搭配使用,生成一個數組,用於獲取函數多餘的參數:

let sum = (a, b, ...m)=>{
  let total = 0;
  for(var i of m){
    total += i;
  }
  console.log(`total:${total}`);
}

sum(1,2,3,4); // total:7

箭頭函數:

使用箭頭函數可以創建語法更爲簡潔的函數。

箭頭函數不會創建自己的this參數,它將繼承使用執行上下文的this值。

const values = [0, 3, 2, 5, 7, 4, 8, 1];

//函數的參數爲空或者不止一個時,必須使用括號
values.sort((v1, v2) => v1 - v2);
//當函數的語句不止一行時,必須給代碼塊加上大括號,並使用return語句返回
//等同於
values.sort((v1, v2) => {return v1 - v2;});

//如果直接返回一個對象,則需要給對象加上括號,否則會報錯
let getTempItem = id => ({ id: id, name: "Temp" });

//箭頭函數和變量解構一起使用
const full = ({ first, last }) => first + ' ' + last;
// 等同於
function full(person) {
  return person.first + ' ' + person.last;
}

變量解構賦值及擴展運算符

三點運算符 ... 的應用:rest參數及擴展運算符。

rest參數在上面已經演示過,下面作爲擴展運算符使用:

數組的解構賦值:

let [a, b, c] = [1, 2, 3];

console.log(...[1,2,3]);
// 1 2 3

// 用來實現concat的效果
let arr1=[1,2]; let arr2=[3,4];
console.log(...[...arr1, ...arr2]);
// 1 2 3 4
let [m, ...n] = [1,2,3,4];
console.log(n); //Array(3)

let [a,b,c] = 'ES6';
console.log(a,b,c); //E S 6

//字符串轉化爲數組
let arr = [...'ES6'];
console.log(arr); //Array(3)

Promise使用

以前我們通過callback函數和事件來實現異步操作,層層嵌套,金字塔式,使代碼非常臃腫。

ES6提供了Promise對象,裏面保存着某個未來纔會結束的事件,從它可以獲取異步操作的消息。

這裏只介紹一下常見用法,詳情請看阮一峯ES6詳解

  • 一個利用Promise異步加載圖片的例子:

    let loadImageAsync(url) {
      //返回一個Promise實例對象
      return new Promise(function(resolve, reject){
        const image = new Image();
        image.onload = function() {
          resolve(image);
          //resolve函數的作用是,將Promise對象的狀態從“未完成”變爲“成功”
          //在異步操作成功時調用,並將異步操作的結果,作爲參數傳遞出去
        };
        image.onerror = function {
          reject(new Error('Could not load image at' + url));
          //reject函數的作用是,將Promise對象的狀態從“未完成”變爲“失敗”
          //在異步操作失敗時調用,並將異步操作報出的錯誤,作爲參數傳遞出去
        };
        image.src = url;
      });
    };
    
    //使用then方法來爲Promise實例添加狀態改變時的回調函數
    //第一個參數是resolved狀態的回調函數,第二個參數(可選)是rejected狀態的回調函數。
    loadImageAsync(url).then((res) => {
      document.body.appendChild(res);
      //此處還可以return一個新的Promise,後面繼續指定then
    }).catch((err) => {
      console.log("rejected:", err);
    });
    //catch用來捕獲rejected狀態,也可以把該回調寫入then(resolve回調, rejected回調)
    
  • 如果使用then方法,依次指定了多個回調函數。第一個回調函數完成以後,會將返回結果作爲參數,傳入第二個回調函數。

  • 前一個回調函數可能返回一個Promise對象,後一個回調函數就會等待該Promise對象狀態發生變化,纔會被調用。

    例如:

    loadImageAsync(url_1).then((res)=>{
      return loadInfo(url_2);
    }).then(function funcA(resA) {
      console.log("resolved: ", resA);
    }, function funcB(err){
      console.log("rejected: ", err);
    });
    

    第一個then方法指定的回調函數,返回的是另一個Promise對象。這時,第二個then方法指定的回調函數,就會等待這個新的Promise對象狀態發生變化。如果變爲resolved,就調用funcA,如果狀態變爲rejected,就調用funcB

  • 如果要同時使用多個Promise,還可以用Promise.all():

    Promise.all([checkLogin(), getUserInfo()]).then(([res1, res2]) => {
      console.log(res1, res2);
    });
    

ES6的模塊化

之前已經在模塊化規範裏詳細介紹過:ES6模塊化規範


後續新增特性

ES6新增的內容很多,大部分常用的不再贅述,有一些容易混淆需注意的,如:

  • Object.keys()(ES5新增)

    • 返回對象所有的可枚舉屬性,不包括繼承過來的屬性或方法
    • 注意:如果是數組,遍歷時返回的是索引屬性(即0、1、2…)
    • for...in(非新增)是遍歷一個對象的可枚舉屬性,包括繼承過來的屬性或方法
  • for...of(ES6新增)遍歷可迭代對象定義要迭代的數據

  • for…in和for…of的區別

ES6以後,基本每年發佈一次新的ES,所以特性增加的較少。

ES7新增

  • Array.prototype.includes()判斷數組是否包含指定值

  • 指數操作符 **

ES8新增

  • async/await 讓異步函數寫得更加流暢自然

  • Object.values()
    返回對象自身的所有屬性的值的數組,不包括繼承的值

  • Object.entries()
    返回一個給定對象自身可枚舉屬性的鍵值對的數組,包含的鍵值對也是數組形式
    不包括繼承值

  • 函數參數後允許添加逗號
    主要是用於多人協作開發減少不必要的行變更

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章